Access "Login with Ace Data Cloud" (OAuth 2.0)
Enable your product to support "Login with Ace Data Cloud" and, after user authorization, act on behalf of the user to read and write their Ace Data Cloud resources (profile, API Token, subscriptions, usage, orders, etc.). The underlying mechanism is the standard OAuth 2.0 Authorization Code Flow + PKCE, which is completely consistent with the login methods of GitHub / Google — any existing OAuth client library you have can be used directly.
Suitable Scenarios: You are developing a third-party application / Agent / MCP client / automation workflow and want users to log in with their Ace Data Cloud account with one click, accessing their resources on the platform as needed, without requiring users to manually copy and paste the API Key.
¶ Terminology & Endpoint Quick Reference
All endpoints are at https://auth.acedata.cloud, and you can always get the latest address through the discovery endpoint:
curl https://auth.acedata.cloud/.well-known/oauth-authorization-server
| Purpose | Endpoint |
|---|---|
| Discovery Document | GET /.well-known/oauth-authorization-server |
| User Authorization Page (Browser Redirect) | GET https://auth.acedata.cloud/oauth2/authorize |
| Token Endpoint (Exchange / Refresh token) | POST https://auth.acedata.cloud/oauth2/token |
| Revoke Token | POST https://auth.acedata.cloud/oauth2/revoke |
| User Information (UserInfo) | GET https://auth.acedata.cloud/api/v1/users/me |
| Application Registration Management (Self-service) | https://auth.acedata.cloud/user/oauth-apps |
Supported capabilities: response_type=code, grant_types=authorization_code, refresh_token, code_challenge_methods=S256, plain, client authentication methods client_secret_post (confidential client) / none (PKCE public client).
¶ Permission Scope (Scope)
Apply for "least privilege," and users will see each permission you request on the authorization page.
Identity (OIDC Compatible)
| Scope | Meaning | /users/me Return Fields |
|---|---|---|
openid |
User unique identifier | id |
profile |
Basic information | username, nickname, avatar, is_verified, date_joined |
email |
email |
|
phone |
Phone number (sensitive) | phone, region |
Platform Resource
| Scope | Meaning |
|---|---|
applications:read / applications:write |
Read / Modify user service subscriptions and quotas |
credentials:read / credentials:write |
Read / Create Revoke user API Token |
usage:read |
Read user call history |
orders:read / orders:write |
Read orders / Place orders and initiate payment |
Aggregation (Automatically Expanded)
| Scope | Expanded To |
|---|---|
platform:read |
applications:read + credentials:read + usage:read + orders:read |
platform:write |
applications:write + credentials:write + orders:write |
platform |
platform:read + platform:write |
Special
| Scope | Meaning |
|---|---|
offline_access |
Issue Refresh Token (if not requested, only Access Token is issued, and re-authorization is required when it expires) |
Typical combinations: Third-party "one-click login" =
openid profile; MCP / IDE client needs to automatically configure Key =openid profile credentials:read credentials:write; Full management console =openid profile email platform offline_access.
¶ Step 1: Register an OAuth Application
Open auth.acedata.cloud/user/oauth-apps → "Create Application," fill in:
- Application Name / Description / Logo: Will be displayed on the user's authorization consent page.
- Client Type:
- Confidential — You have a backend that can securely store
client_secret(Web service, backend service). - Public — Pure frontend / desktop / CLI / mobile, cannot store secrets, must use PKCE.
- Confidential — You have a backend that can securely store
- Redirect URIs: The address to which users are redirected after authorization is complete, must exactly match the
redirect_uriyou passed when initiating authorization, can fill in multiple. - Permission Scope (Scopes): Check the scopes you need from the previous section.
After saving, obtain client_id; confidential clients will also once display client_secret—save it immediately, as it cannot be viewed again after closing (can be regenerated on the details page under "Rotate Secret," and the old secret will become invalid immediately).
Each account can create a maximum of 20 OAuth applications.
¶ Step 2: Redirect the User to the Authorization Page
In your application, redirect the user's browser to the authorization page with the query parameters:
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> # Required for public clients
&code_challenge_method=S256 # Required for public clients
state: A randomly generated string that is returned as is during the callback, used for CSRF protection, must be validated.- PKCE (mandatory for public clients, recommended for confidential clients): First generate a random
code_verifier, then calculatecode_challenge = BASE64URL( SHA256( code_verifier ) ), place thecode_challengein the authorization URL, keep thecode_verifierfor use in Step 4.
After the user logs in and clicks "Agree," the browser will be redirected back to:
<redirect_uri>?code=<authorization code>&state=<state returned as is>
If the user declines: <redirect_uri>?error=access_denied&error_description=...&state=....
The authorization code is valid for 10 minutes and can only be used once.
¶ Step 3: Exchange the Authorization Code for a Token
In your backend (confidential client) or client (PKCE public client), call the token endpoint using the code.
Confidential Client (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>
Public Client (PKCE, without client_secret):
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 in Step 2> \
-d redirect_uri=<callback address>
Successful response (the refresh_token only appears when offline_access is requested):
{
"access_token": "<JWT>",
"token_type": "Bearer",
"expires_in": 1296000,
"scope": "openid profile credentials:read",
"refresh_token": "<JWT, only when offline_access>"
}
access_token is a JWT that contains the scope claims; valid for 15 days (expires_in in seconds). The Refresh Token is valid for 30 days.
¶ Step 4: Call the API with the Access Token
Place the token in the Authorization: Bearer header.
Read User Information (UserInfo, fields filtered by authorized scope):
curl https://auth.acedata.cloud/api/v1/users/me \
-H "Authorization: Bearer <access_token>"
Call Platform Resource API (api.acedata.cloud, authorized by scope). For example, if credentials:read is granted:
curl https://api.acedata.cloud/api/v1/credentials/ \
-H "Authorization: Bearer <access_token>"
The platform backend will validate the scope claims in the JWT—tokens can only access resources authorized by the user. If unauthorized resources are accessed, a 403 will be returned.
¶ Refresh Token
After the Access Token expires, use the Refresh Token to obtain a new pair of tokens (requires that offline_access was initially requested):
curl -X POST https://auth.acedata.cloud/oauth2/token \
-d grant_type=refresh_token \
-d refresh_token=<your refresh_token>
The return structure is the same as in step 3; the scope will be retained as is from the original authorization. The old Refresh Token becomes invalid (rotated) after refreshing, please save the new one.
¶ Revoke Token
curl -X POST https://auth.acedata.cloud/oauth2/revoke \
-d token=<access_token or refresh_token>
¶ Real Case: This is how our own MCP server connects
The 15+ MCP servers of Ace Data Cloud (NanoBanana, Midjourney, Suno, Seedance, Kling…) that appear in Claude Desktop / Cursor with the "Sign in with Ace Data Cloud" link follow this process: they are all registered as public (PKCE) type OAuth applications, requesting credentials related scopes. After user authorization, the MCP server can call api.acedata.cloud on behalf of the user—without the user manually pasting the API Key. Your connection method is exactly the same as theirs.
¶ Common Errors
Error responses are uniformly formatted as { "error": "<code>", "error_description": "<human-readable explanation>" }:
| error | Meaning / Troubleshooting |
|---|---|
invalid_request |
Missing or illegal parameters (e.g., did not send code / client_id) |
invalid_client |
client_id does not exist, application is disabled, or client_secret is incorrect |
invalid_grant |
Authorization code does not exist / has expired (>10 minutes) / has been used / PKCE verification failed / redirect_uri does not match the authorization |
access_denied |
User clicked "Deny" on the authorization page |
unsupported_grant_type |
grant_type is not authorization_code or refresh_token |
¶ Rate Limits
| Item | Value |
|---|---|
| Maximum number of OAuth applications per account | 20 |
| Authorization code validity period | 10 minutes, single use |
| Access Token validity period | 15 days |
| Refresh Token validity period | 30 days (rotated) |
redirect_uri |
Must match the registered value exactly |
client_secret |
Displayed only once during creation / rotation, stored on the server as SHA-256 hash |
