Token endpoint

Token endpoint

Authorization code exchange and Proxy client credentials, with claims and errors.

Checked against the Evaluation environment, Console 0.10.1 / 0.14.1, on October 19, 2026. Release status

Endpoint

http
POST https://core.api.aigw.eval.loginid.ai/oauth2/tokenContent-Type: application/x-www-form-urlencoded

The token endpoint lives on the core host, not on the per-Resource gateway path. Read it from the token_endpoint field of the Resource's discovery document instead of hard-coding it.

GrantUsed byStatus
authorization_codeAgents, after the user approvesSupported
client_credentialsMCP and UCP services (Proxy clients)Supported
refresh_tokenAgents, to renew an expired access tokenUnverified

Client authentication

ClientMethodStatus
Agent (registered with DCR)client_secret_post: client_id and client_secret in the form bodySupported
Agent (registered with DCR)client_secret_basic: HTTP Basic headerUnsupported
Proxy client (created in Console)HTTP Basic header with the Proxy client ID and secretSupported

Register agents with "token_endpoint_auth_method": "client_secret_post". Registering with client_secret_basic is not implemented for agents in this release.

Authorization code grant

Exchange the code from the authorization endpoint for the user's AIGW tokens. PKCE is required.

Form parameters

grant_type
stringRequired
authorization_code
code
stringRequired
The code returned to your redirect URI. Single use.
redirect_uri
stringRequired
Exactly the redirect URI sent on the authorization request.
client_id
stringRequired
From Dynamic Client Registration.
client_secret
stringRequired
From Dynamic Client Registration.
code_verifier
stringRequired
The PKCE verifier whose S256 hash you sent as code_challenge.
curl -s -X POST "https://core.api.aigw.eval.loginid.ai/oauth2/token" \  -H "Content-Type: application/x-www-form-urlencoded" \  --data-urlencode "grant_type=authorization_code" \  --data-urlencode "code=$CODE" \  --data-urlencode "redirect_uri=$REDIRECT_URI" \  --data-urlencode "client_id=$CLIENT_ID" \  --data-urlencode "client_secret=$CLIENT_SECRET" \  --data-urlencode "code_verifier=$CODE_VERIFIER"
Response (abbreviated example)200 OKjson
{  "access_token": "<AIGW access token, a JWT>",  "id_token": "<ID token>",  "refresh_token": "<refresh token>",  "scope": "openid search:read"}

Response fields

access_token
JWT
The AIGW access token. The agent sends it as Authorization: Bearer to the MCP or UCP service. Claims are listed below.
id_token
JWT
Identifies the user to your agent. Contains personal data: do not log it or forward it to services.
refresh_token
string
Renews the access token. See the refresh grant, Unverified.
scope
string
Space-separated scopes granted.

expires_in and token_type are not documented for this grant. Read exp from the access token instead.

Client credentials grant

MCP and UCP services use this grant to get a Proxy token. You need it, together with the user's AIGW token, to redeem the merchant token. Create the Proxy client in the Console under your Project.

Request

Authorization
headerRequired
Basic base64(client_id:client_secret) of the Proxy client.
grant_type
stringRequired
client_credentials
curl -s -X POST "https://core.api.aigw.eval.loginid.ai/oauth2/token" \  -u "$PROXY_CLIENT_ID:$PROXY_CLIENT_SECRET" \  -H "Content-Type: application/x-www-form-urlencoded" \  --data-urlencode "grant_type=client_credentials"
Response (abbreviated example)200 OKjson
{  "access_token": "<Proxy access token>",  "expires_in": 3599}

Cache the Proxy token and request a new one shortly before expires_in runs out. It is not tied to any user, so one token serves every request from your service.

Refresh token grant

Unverified A refresh_token is issued, but renewing with it has not been confirmed end to end in this release. The request below follows RFC 6749 section 6. If it fails, send the user through the authorization flow again.

Requestbash
curl -s -X POST "https://core.api.aigw.eval.loginid.ai/oauth2/token" \  -H "Content-Type: application/x-www-form-urlencoded" \  --data-urlencode "grant_type=refresh_token" \  --data-urlencode "refresh_token=$REFRESH_TOKEN" \  --data-urlencode "client_id=$CLIENT_ID" \  --data-urlencode "client_secret=$CLIENT_SECRET"

Access token claims

ClaimMeaning
issThe core issuer. Must equal the issuer in the Resource's discovery document.
audThe resource indicator the token is bound to. Services must check it is theirs.
subAn opaque user id, for example sub_…. Stable per user; contains no personal data.
expExpiry as a Unix timestamp.
ext.acrAuthentication assurance level reached by the user, for example a value ending in :al2.
ext.amrMethods the user authenticated with, for example ["mfa", "kba"].
ext.agentThe agent the token was issued to.
ext.actThe actor acting on the user's behalf.
ext.project_idThe Console Project that issued the token.

The full structure of ext.agent and ext.act is not documented for this release. Treat unknown fields as optional.

Validate tokens

If you run an MCP or UCP service, validate every AIGW token before you act on it:

  • Verify the signature with keys from the jwks_uri in discovery. Cache keys by kid and refetch when you see an unknown kid, so key rotation never breaks you.
  • Check iss equals the discovery issuer and aud contains your resource indicator.
  • Reject tokens past exp. Allow at most a small clock skew.
  • Use sub as the user key. Never ask the agent for the user's email or name.

Errors

Unverified Error responses from this endpoint have not been documented for this release. The core token service is an OAuth 2.0 server, so expect the standard RFC 6749 section 5.2 format: HTTP 400 (or 401 for client authentication failures) with a JSON body.

Error body (standard format)400 Bad Requestjson
{  "error": "invalid_grant",  "error_description": "<human-readable detail>"}
errorCommon causeRecovery
invalid_requestA required parameter is missing or repeatedCheck the parameter table. Send the body as form data, not JSON.
invalid_clientWrong client ID or secret, or an unsupported authentication methodAgents: send credentials in the body (client_secret_post). Proxy clients: use HTTP Basic. Rotate the secret in the Console if it may be wrong.
invalid_grantCode expired or already used, redirect URI mismatch, or wrong code_verifierStart a fresh authorization request with a new PKCE pair. Do not retry the same code.
unauthorized_clientThe client is not allowed this grant typeRegister the agent with the grant types it uses, or use a Proxy client for client_credentials.
unsupported_grant_typeMisspelled or unsupported grant_typeUse one of the grants listed on this page.
invalid_scopeA scope not configured on the ResourceRequest only scopes configured on the Resource in the Console.

Limits

Rate limits, token lifetimes other than the Proxy token's 3599 seconds, and retry guidance are not documented for this release. Until they are, retry only on network errors and 5xx responses, with exponential backoff, and never retry invalid_grant. See the production checklist.