CAIRLDocs
Integration

OAuth Token Revocation

Revoke a previously issued access token via RFC 7009.

Overview

CAIRL's OAuth provider implements RFC 7009 — OAuth 2.0 Token Revocation. Partners can revoke a previously issued access token at any time, after which userinfo and any other authenticated request using that token return 401 Unauthorized.

This endpoint is the partner-initiated counterpart to the user-initiated revocation that fires when an end-user removes a connected app from their CAIRL dashboard. Both paths flip the same is_revoked flag on the access-token row.


Endpoint

POST /api/oauth/revoke

Content-Type: application/x-www-form-urlencoded (RFC 7009 §2.1) — JSON also accepted for partner ergonomics.

Request body

FieldRequiredDescription
tokenYesThe access token to revoke.
token_type_hintNoPer RFC 7009 §2.1; if present, must be access_token. CAIRL does not currently issue refresh tokens.
client_idYesYour partner API key (the same client_id value used at the /oauth/token endpoint).
client_secretYesYour partner API key secret.

Response

Always 200 for any token-related outcome per RFC 7009 §2.2 — a valid token, an unknown token, an expired token, a token belonging to a different partner, and an already-revoked token all produce the same response. This prevents an attacker who can reach this endpoint from enumerating valid jti values.

The response body is empty.

StatusMeaning
200The request was processed. The token, if it exists and belongs to your partner, is now revoked.
400Malformed request (missing required fields, wrong Content-Type, malformed JSON).
401Invalid client_id or client_secret.
429Rate limit exceeded. The Retry-After header indicates seconds until the next attempt.

Behavior

  • The endpoint authenticates your client using the same hashing path as /oauth/token. A request with bad credentials returns 401 immediately and never touches the token DB.
  • Once authenticated, the JWT signature on the submitted token is verified. If the JWT cannot be verified (bad signature, expired key), the response is still 200 with no DB write — RFC 7009's no-enumeration property.
  • If the JWT is valid, the access-token row is looked up by jti. The token is flipped to is_revoked = true only if (a) the row exists, (b) it belongs to the authenticated client's partner (cross-partner revocation attempts silently no-op), and (c) it is not already revoked.
  • An audit event oauth.token.revoked is recorded for every successful flip.

Example

curl -X POST https://cairl.app/api/oauth/revoke \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "token=eyJhbGciOiJSUzI1NiI..." \
  -d "client_id=cairl_live_..." \
  -d "client_secret=cairl_live_..."

HTTP/1.1 200 OK
Cache-Control: no-store

Latency expectation

After a successful revocation, subsequent calls to /api/oauth/userinfo using the same token return 401 within 1 second. Existing in-flight requests are not interrupted.


Errors

Error codeStatusWhen
invalid_request400Missing token / client_id / client_secret, or non-form/JSON body.
invalid_client401Unknown client_id, wrong client_secret, or inactive partner key.
rate_limit_exceeded429Per-client revocation rate limit hit; check Retry-After.

See also: Errors.

On this page