Skip to content

POST /api/oauth/token

Exchange an authorization code for tokens, or refresh an access token.

Endpoint

text
POST /api/oauth/token

Content Type

Send application/x-www-form-urlencoded.

The current implementation expects form fields, not a JSON body.

Client Authentication

Supported methods:

  • client_secret_basic
  • client_secret_post

Authorization Code Grant

Required form fields

FieldValue
grant_typeauthorization_code
codeauthorization code from /api/oauth/authorize
redirect_urimust match the original authorization request
code_verifierrequired if the authorization code was issued with PKCE
client_idrequired unless sent via HTTP Basic auth
client_secretrequired unless sent via HTTP Basic auth

Example Request

bash
curl -X POST https://portal.eprospera.com/api/oauth/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=authorization_code" \
  -d "code=$CODE" \
  -d "code_verifier=$CODE_VERIFIER" \
  -d "redirect_uri=$REDIRECT_URI"

Clients using PKCE must send the original code_verifier from the authorization request or the token exchange fails with invalid_grant.

Refresh Token Grant

Required form fields

FieldValue
grant_typerefresh_token
refresh_tokenpreviously issued refresh token
client_idrequired unless sent via HTTP Basic auth
client_secretrequired unless sent via HTTP Basic auth

Optional form fields

FieldDescription
scopeOptional reduced scope set. Must be a subset of the original granted scopes and still allowed for the client.

Example Request

bash
curl -X POST https://portal.eprospera.com/api/oauth/token \
  -u "$CLIENT_ID:$CLIENT_SECRET" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "refresh_token=$REFRESH_TOKEN"

Success Response

Common fields

FieldTypeDescription
access_tokenstringBearer access token.
token_typestringAlways Bearer.
expires_innumberAccess-token lifetime in seconds. Currently 3600.
scopestringSpace-delimited granted scopes.

Conditional fields

FieldWhen present
id_tokenIncluded when the granted scopes include openid.
refresh_tokenIncluded when the granted scopes include offline_access. Refresh tokens rotate on every successful refresh.

Example Response

json
{
  "access_token": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "openid profile email offline_access",
  "id_token": "eyJ...",
  "refresh_token": "rt_..."
}

Error Responses

400 Bad Request

json
{
  "error": "invalid_request"
}
json
{
  "error": "invalid_grant"
}
json
{
  "error": "invalid_scope"
}
json
{
  "error": "unsupported_grant_type"
}

401 Unauthorized

json
{
  "error": "invalid_client"
}

500 Internal Server Error

json
{
  "error": "internal_server_error"
}

Notes

  • Authorization codes are single-use and short-lived.
  • Refresh-token reuse or use after revocation invalidates the token family.
  • Responses include Cache-Control: no-store and Pragma: no-cache.