Appearance
POST /api/oauth/token
Exchange an authorization code for tokens, or refresh an access token.
Endpoint
text
POST /api/oauth/tokenContent Type
Send application/x-www-form-urlencoded.
The current implementation expects form fields, not a JSON body.
Client Authentication
Supported methods:
client_secret_basicclient_secret_post
Authorization Code Grant
Required form fields
| Field | Value |
|---|---|
grant_type | authorization_code |
code | authorization code from /api/oauth/authorize |
redirect_uri | must match the original authorization request |
code_verifier | required if the authorization code was issued with PKCE |
client_id | required unless sent via HTTP Basic auth |
client_secret | required 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
| Field | Value |
|---|---|
grant_type | refresh_token |
refresh_token | previously issued refresh token |
client_id | required unless sent via HTTP Basic auth |
client_secret | required unless sent via HTTP Basic auth |
Optional form fields
| Field | Description |
|---|---|
scope | Optional 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
| Field | Type | Description |
|---|---|---|
access_token | string | Bearer access token. |
token_type | string | Always Bearer. |
expires_in | number | Access-token lifetime in seconds. Currently 3600. |
scope | string | Space-delimited granted scopes. |
Conditional fields
| Field | When present |
|---|---|
id_token | Included when the granted scopes include openid. |
refresh_token | Included 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-storeandPragma: no-cache.