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).

FieldTypeRequiredDescription
grant_typestringYesrefresh_token
refresh_tokenstringYesThe current refresh token of the session.
client_idstringYesThe client the refresh token was issued to.
client_secretstringNoConfidential 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.

StatuserrorWhen
400invalid_requestrefresh_token is missing or client_id is malformed.
400invalid_grantThe refresh token was rejected (unknown, expired, already spent), belongs to another client, or its client no longer exists.
400invalid_clientA confidential client failed to authenticate, or a disallowed IP.
400invalid_requestThe host is not an org.
400unsupported_grant_typegrant_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_…