Refresh a token
Trade a refresh token for a new access token and a new refresh token.
POST /oauth/token
Returns a new access token and a new refresh token. Refresh tokens rotate: the one you sent is spent. Presenting a spent one again ends the whole session, on the assumption that someone else has a copy.
Authorization
The refresh token is the credential; no Bearer token. A confidential client also authenticates with its secret. See Client authentication.
Body
Form-encoded (application/x-www-form-urlencoded).
| Field | Type | Required | Description |
|---|---|---|---|
grant_type | string | Yes | refresh_token |
refresh_token | string | Yes | The current refresh token of the session. |
client_id | string | Yes | The client the refresh token was issued to. |
client_secret | string | No | Confidential clients using client_secret_post. |
Response
200, with Cache-Control: no-store.
{
"token_type": "Bearer",
"access_token": "eyJ…",
"expires_in": 3600,
"refresh_token": "…"
}
Errors
Every refusal is 400 with an RFC 6749 code and nothing else.
| Status | error | When |
|---|---|---|
400 | invalid_request | refresh_token is missing or client_id is malformed. |
400 | invalid_grant | The refresh token was rejected (unknown, expired, already spent), belongs to another client, or its client no longer exists. |
400 | invalid_client | A confidential client failed to authenticate, or a disallowed IP. |
400 | invalid_request | The host is not an org. |
400 | unsupported_grant_type | grant_type is not one of the five the endpoint accepts. |
Example
curl -X POST https://acme.loginwith.dev/oauth/token \
-d grant_type=refresh_token \
-d refresh_token=… \
-d client_id=cli_…