Rotate a refresh token and issue a new access token.
const url = 'https://connect-api.sudomimus.com/refresh';const options = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{"refreshToken":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://connect-api.sudomimus.com/refresh \ --header 'Content-Type: application/json' \ --data '{ "refreshToken": "example" }'Issues a new access token AND a new refresh token, atomically
invalidating the presented refresh token. The Connect service
implements OAuth 2.1 BCP §4.14.2 strict refresh-token rotation:
every successful /refresh rotates the refresh token, and any
subsequent presentation of the parent token (the one just
consumed) is treated as evidence of compromise.
On compromise, the entire refresh-token family that the replayed
token belongs to is revoked in a single sweep and the caller must
re-authenticate via the normal Connect inquiry flow
(/establish → /status-poll → /redeem). The same outcome
applies when a concurrent rotation race is lost — per BCP §4.14.2
a perfectly-timed retry is indistinguishable from an attacker
racing the legitimate caller, so both paths count as compromise.
Request Body required
Section titled “Request Body required ”object
Example generated
{ "refreshToken": "example"}Responses
Section titled “ Responses ”New access token and rotated refresh token issued.
object
Per-claim view across the three shareable claims — why a claim is or is not present in the minted token (policy OFF, never asked, declined, or granted).
object
One shareable claim: what the application requests (requirement)
joined with the user’s standing decision (state). UNKNOWN means
the user was never asked; DENIED means the user explicitly
declined.
object
The developer’s policy for the claim. SYNTHETIC guarantees the
claim is present but permits a generated placeholder (a stand-in
name, a proxy email) when the user has not shared real data —
unlike REQUIRED it never blocks issuance or raises an errand.
One shareable claim: what the application requests (requirement)
joined with the user’s standing decision (state). UNKNOWN means
the user was never asked; DENIED means the user explicitly
declined.
object
The developer’s policy for the claim. SYNTHETIC guarantees the
claim is present but permits a generated placeholder (a stand-in
name, a proxy email) when the user has not shared real data —
unlike REQUIRED it never blocks issuance or raises an errand.
One shareable claim: what the application requests (requirement)
joined with the user’s standing decision (state). UNKNOWN means
the user was never asked; DENIED means the user explicitly
declined.
object
The developer’s policy for the claim. SYNTHETIC guarantees the
claim is present but permits a generated placeholder (a stand-in
name, a proxy email) when the user has not shared real data —
unlike REQUIRED it never blocks issuance or raises an errand.
Short-lived access token (JWT). Decode its body to
AccessTokenBody (see schema) — the application-visible user
key is the subject (sector subject) claim.
Newly issued refresh token (JWT); body is RefreshTokenBody.
The presented refresh token is invalidated atomically as part
of the same call; re-presenting it is treated as compromise
under OAuth 2.1 BCP §4.14.2 strict rotation.
Example
{ "claims": { "email": { "requirement": "OFF", "state": "UNKNOWN" }, "firstName": { "requirement": "OFF", "state": "UNKNOWN" }, "lastName": { "requirement": "OFF", "state": "UNKNOWN" } }}Reason AccountNotFound — the account behind the refresh token
could not be resolved.
Error response body. The Connect service emits { "reason": "<SymbolDescription>" }
for known failure modes. When the reason symbol’s description begins with
PRIVATE, the body is empty (zero bytes) and only the HTTP status carries
signal — both reason and the body itself are absent in that case.
object
Stable machine-readable reason code.
Example generated
{ "reason": "example"}Refresh token rejected. The reason distinguishes:
RefreshTokenNotFound— token cannot be resolved (unknownjti, wrong signature, or otherwise invalid).RefreshTokenSuspended— the refresh-token session is suspended.RefreshTokenExpired— the token is past itsexp.RefreshTokenFamilyCompromised— the presented token had already been rotated; the whole family has now been revoked.RefreshTokenRotationRaceLost— a concurrent rotation won the conditional write. Per OAuth 2.1 BCP §4.14.2 this is also treated as compromise and the family is revoked.
Error response body. The Connect service emits { "reason": "<SymbolDescription>" }
for known failure modes. When the reason symbol’s description begins with
PRIVATE, the body is empty (zero bytes) and only the HTTP status carries
signal — both reason and the body itself are absent in that case.
object
Stable machine-readable reason code.
Example generated
{ "reason": "example"}The attempt was refused. The reason distinguishes:
AccountDisabled— the account behind the refresh token is disabled.AccountDeleted— the account has been erased.ClaimConsentRequired— a REQUIRED claim is no longer satisfied by a standing grant (e.g. the user revoked it); the grant must be re-established through an interactive browser login.
Error response body. The Connect service emits { "reason": "<SymbolDescription>" }
for known failure modes. When the reason symbol’s description begins with
PRIVATE, the body is empty (zero bytes) and only the HTTP status carries
signal — both reason and the body itself are absent in that case.
object
Stable machine-readable reason code.
Example generated
{ "reason": "example"}default
Section titled “default ”Error response.
Error response body. The Connect service emits { "reason": "<SymbolDescription>" }
for known failure modes. When the reason symbol’s description begins with
PRIVATE, the body is empty (zero bytes) and only the HTTP status carries
signal — both reason and the body itself are absent in that case.
object
Stable machine-readable reason code.
Example generated
{ "reason": "example"}