Skip to main content

Token Endpoint

The token endpoint is where your application exchanges credentials for access tokens. It supports several grant types: authorization code (for interactive user logins), client credentials (for service-to-service calls), refresh token (for extending sessions without re-prompting the user), and token exchange (for delegation and impersonation). This endpoint is defined by RFC 6749 — the OAuth 2.0 Authorization Framework, the core specification that defines the authorize and token endpoints and the standard grant types.

POST /orgs/{orgId}/api/v1/oauth/token

Authorization Code Grant

Exchange an authorization code (received from the authorize endpoint) for access and refresh tokens. This is the most common flow for user authentication.

Request Parameters

ParameterRequiredDescription
grant_typeYesauthorization_code
codeYesThe authorization code from the callback
redirect_uriYesMust match the URI used in the authorization request
client_idYesYour application's client ID
client_secretConfidential clientsYour application's client secret (not needed for public clients with PKCE)
code_verifierIf PKCE usedThe original code_verifier that matches the code_challenge

Example Request

curl -X POST https://app.lumoauth.dev/orgs/acme-corp/api/v1/oauth/token \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "grant_type=authorization_code" \
-d "code=SplxlOBeZQQYbYS6WxSbIA" \
-d "redirect_uri=https://myapp.com/callback" \
-d "client_id=abc123def456" \
-d "client_secret=YOUR_CLIENT_SECRET" \
-d "code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk"

Response

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4...",
"scope": "openid profile email",
"id_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
}

Client Credentials Grant

Authenticate your application as itself, without a user. Use this for server-to-server communication, cron jobs, background workers, or AI agents.

Request Parameters

ParameterRequiredDescription
grant_typeYesclient_credentials
client_idYesYour application's client ID
client_secretYesYour application's client secret
scopeNoSpace-separated scopes (defaults to the client's registered scopes)

Example Request

curl -X POST https://app.lumoauth.dev/orgs/acme-corp/api/v1/oauth/token \
-u "CLIENT_ID:CLIENT_SECRET" \
-d "grant_type=client_credentials" \
-d "scope=read:reports write:data"

Response

{
"access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "read:reports write:data"
}

Refresh Token Grant

Get a new access token using a refresh token, without requiring the user to log in again. Refresh tokens typically last 30 days.

Request Parameters

ParameterRequiredDescription
grant_typeYesrefresh_token
refresh_tokenYesThe refresh token from a previous token response
client_idYesYour application's client ID
client_secretConfidential clientsYour application's client secret

Example Request

curl -X POST https://app.lumoauth.dev/orgs/acme-corp/api/v1/oauth/token \
-u "CLIENT_ID:CLIENT_SECRET" \
-d "grant_type=refresh_token" \
-d "refresh_token=dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4..."
Refresh Token Rotation

LumoAuth rotates refresh tokens. Each time you use a refresh token, a new one is issued and the old one is invalidated. If the old token is used again, the entire token family is revoked — this detects theft.

Token Exchange Grant

Token exchange (RFC 8693 — OAuth 2.0 Token Exchange: lets a service swap one token for another, the mechanism behind delegation and impersonation) enables scenarios like:

  • Impersonation — a service acts as a user.
  • Delegation — a service acts on behalf of a user, with an audit trail.
  • Workload identity — exchange external tokens (AWS, Kubernetes) for LumoAuth tokens.

Request Parameters

ParameterRequiredDescription
grant_typeYesurn:ietf:params:oauth:grant-type:token-exchange
subject_tokenYesThe token representing the subject (user or service)
subject_token_typeYesurn:ietf:params:oauth:token-type:access_token or urn:ietf:params:oauth:token-type:jwt
actor_tokenFor delegationToken of the service acting on behalf of the subject
actor_token_typeIf actor_tokenType of the actor token

Delegation Example

Service B acts on behalf of User A. The resulting token has an act claim that records the chain of identity.

curl -X POST https://app.lumoauth.dev/orgs/acme-corp/api/v1/oauth/token \
-u "CLIENT_ID:CLIENT_SECRET" \
-d "grant_type=urn:ietf:params:oauth:grant-type:token-exchange" \
-d "subject_token=USER_A_ACCESS_TOKEN" \
-d "subject_token_type=urn:ietf:params:oauth:token-type:access_token" \
-d "actor_token=SERVICE_B_ACCESS_TOKEN" \
-d "actor_token_type=urn:ietf:params:oauth:token-type:access_token"

Resulting JWT Claims

{
"sub": "user_a",
"act": {
"sub": "service_b"
},
"iss": "https://app.lumoauth.dev",
"exp": 1704067200
}

The act (actor) claim indicates that service_b is acting on behalf of user_a. This creates a complete audit trail.

Error Responses

Token endpoint errors follow the OAuth 2.0 specification:

{
"error": "invalid_grant",
"error_description": "Authorization code is invalid, expired, or revoked"
}
ErrorDescription
invalid_requestMissing or invalid parameters
invalid_clientClient authentication failed
invalid_grantAuthorization code or refresh token is invalid or expired
invalid_scopeRequested scope is not allowed for this client
unsupported_grant_typeThe grant type is not supported