DEV Community

Cover image for How to Implement Ace Data Cloud Login with OAuth 2.0 and PKCE
Germey
Germey

Posted on • Originally published at platform.acedata.cloud

How to Implement Ace Data Cloud Login with OAuth 2.0 and PKCE

If your app needs to call a user's Ace Data Cloud resources, asking them to copy an API key is usually the worst part of the onboarding flow.

A cleaner approach is OAuth 2.0 Authorization Code Flow with PKCE: the user clicks a login button, approves the requested scopes, and your app receives an access token that can call only the resources the user authorized.

This guide walks through the practical shape of that integration using the public Ace Data Cloud OAuth documentation.

What you can build

The OAuth flow is meant for third-party applications, agents, MCP clients, and automation workflows that want a user to sign in with Ace Data Cloud and then access platform resources on that user's behalf.

The auth base URL is:

https://auth.acedata.cloud
Enter fullscreen mode Exit fullscreen mode

The key endpoints are:

Purpose Endpoint
Discovery document GET /.well-known/oauth-authorization-server
Browser authorization GET https://auth.acedata.cloud/oauth2/authorize
Token exchange or refresh POST https://auth.acedata.cloud/oauth2/token
Revoke token POST https://auth.acedata.cloud/oauth2/revoke
User information GET https://auth.acedata.cloud/api/v1/users/me
OAuth app management https://auth.acedata.cloud/user/oauth-apps

You can fetch the current discovery document with:

curl https://auth.acedata.cloud/.well-known/oauth-authorization-server
Enter fullscreen mode Exit fullscreen mode

Supported capabilities include response_type=code, grant_types=authorization_code, refresh_token, PKCE challenge methods S256 and plain, and client authentication methods client_secret_post for confidential clients or none for public PKCE clients.

Choose scopes with least privilege

Scopes are what make the OAuth flow safer than a copied API key. The user sees the permissions you request, and your token is limited to those permissions.

For identity, the supported scopes include:

  • openid: returns the user's unique id
  • profile: returns fields such as username, nickname, avatar, is_verified, and date_joined
  • email: returns email
  • phone: returns phone and region

For platform resources, the documented scopes include:

  • applications:read and applications:write
  • credentials:read and credentials:write
  • usage:read
  • orders:read and orders:write

There are also aggregate scopes. platform:read expands to applications:read, credentials:read, usage:read, and orders:read. platform:write expands to applications:write, credentials:write, and orders:write. platform expands to both read and write groups.

A minimal sign-in flow might request only openid profile. An MCP or IDE client that needs to configure keys could request openid profile credentials:read credentials:write. Request offline_access only if you need a refresh token.

Register the OAuth application

Create the application at:

https://auth.acedata.cloud/user/oauth-apps
Enter fullscreen mode Exit fullscreen mode

During registration, choose a client type:

  • Confidential: a backend service that can store client_secret
  • Public: frontend, desktop, CLI, or mobile clients that cannot store secrets and must use PKCE

You also configure redirect URIs. The redirect URI must exactly match the redirect_uri you send later in the authorization request. After saving, you receive a client_id. Confidential clients also see a client_secret once, so save it immediately.

Redirect the user to authorize

The browser redirect starts at:

https://auth.acedata.cloud/oauth2/authorize
Enter fullscreen mode Exit fullscreen mode

A typical authorization URL looks like this:

https://auth.acedata.cloud/oauth2/authorize
  ?response_type=code
  &client_id=<your client_id>
  &redirect_uri=<your registered callback address>
  &scope=openid%20profile%20credentials:read
  &state=<random CSRF protection string>
  &code_challenge=<PKCE challenge value>
  &code_challenge_method=S256
Enter fullscreen mode Exit fullscreen mode

Always validate state when the user returns to your redirect URI. It is your CSRF protection value.

For PKCE, generate a random code_verifier, then compute:

code_challenge = BASE64URL(SHA256(code_verifier))
Enter fullscreen mode Exit fullscreen mode

Send the code_challenge in the authorization URL and keep the code_verifier for the token exchange. After approval, the browser returns to:

<redirect_uri>?code=<authorization code>&state=<state returned as is>
Enter fullscreen mode Exit fullscreen mode

If the user denies access, the redirect contains error=access_denied and an error_description.

The authorization code is valid for 10 minutes and can be used only once, so exchange it promptly.

Exchange the code for tokens

Confidential clients exchange the code with client_secret:

curl -X POST https://auth.acedata.cloud/oauth2/token \
  -d grant_type=authorization_code \
  -d code=<code obtained in the previous step> \
  -d client_id=<your client_id> \
  -d client_secret=<your client_secret> \
  -d redirect_uri=<callback address that exactly matches Step 2>
Enter fullscreen mode Exit fullscreen mode

Public PKCE clients exchange the code with code_verifier instead:

curl -X POST https://auth.acedata.cloud/oauth2/token \
  -d grant_type=authorization_code \
  -d code=<code> \
  -d client_id=<your client_id> \
  -d code_verifier=<code_verifier generated earlier> \
  -d redirect_uri=<callback address>
Enter fullscreen mode Exit fullscreen mode

A successful response has this shape:

{
  "access_token": "<JWT>",
  "token_type": "Bearer",
  "expires_in": 1296000,
  "scope": "openid profile credentials:read",
  "refresh_token": "<JWT, only when offline_access>"
}
Enter fullscreen mode Exit fullscreen mode

The access token is a JWT with scope claims and is valid for 15 days. The refresh token appears only when offline_access was requested and is valid for 30 days.

Call APIs with the access token

To read user information, send the token in the Authorization: Bearer header:

curl https://auth.acedata.cloud/api/v1/users/me \
  -H "Authorization: Bearer <access_token>"
Enter fullscreen mode Exit fullscreen mode

The returned fields depend on the identity scopes the user granted.

For platform resource APIs, call api.acedata.cloud with the same bearer token. For example, if credentials:read was granted:

curl https://api.acedata.cloud/api/v1/credentials/ \
  -H "Authorization: Bearer <access_token>"
Enter fullscreen mode Exit fullscreen mode

The platform backend validates the JWT scopes. If the token tries to access an unauthorized resource, the API returns 403.

Refresh and revoke tokens

If you requested offline_access, refresh an expired access token with:

curl -X POST https://auth.acedata.cloud/oauth2/token \
  -d grant_type=refresh_token \
  -d refresh_token=<your refresh_token>
Enter fullscreen mode Exit fullscreen mode

The refresh token is rotated after refresh, so store the new one. To revoke an access or refresh token:

curl -X POST https://auth.acedata.cloud/oauth2/revoke \
  -d token=<access_token or refresh_token>
Enter fullscreen mode Exit fullscreen mode

Handle errors deliberately

OAuth errors use this format:

{
  "error": "<code>",
  "error_description": "<human-readable explanation>"
}
Enter fullscreen mode Exit fullscreen mode

Common cases include invalid_request, invalid_client, invalid_grant, access_denied, and unsupported_grant_type. In practice, most integration bugs are invalid_grant: an expired code, a reused code, PKCE verification failure, or a redirect_uri mismatch.

The docs also note some useful limits: each account can create up to 20 OAuth applications, authorization codes are valid for 10 minutes and single use, access tokens are valid for 15 days, refresh tokens are valid for 30 days and rotated, and redirect_uri must match exactly.

If you are building an agent, MCP client, or internal dashboard, this flow gives users a familiar login experience while keeping access scoped and auditable. The original reference is here: https://platform.acedata.cloud/documents/oauth-integration

Top comments (0)