Token revocation endpoint (RFC 7009)
The rule
POST as.oid4pay.com/oauth/revokeaccepts the token to revoke (AT or RT) plus client authentication- Auth: the token's owning client via
private_key_jwt, OR the principal via Wallet Portal session, OR admin viaX-Internal-Key - Revokes the named token AND cascade-revokes its family (the RT lineage; for AT, the originating RT's family)
- Cascade-revokes any mandate the family was issued under (
Mandate.revoked_atset) - Emits
oid4ac.mandate.revokedSSF event - Advertised in AS metadata as
revocation_endpoint
Wire shape
POST /oauth/revoke HTTP/1.1
Host: as.oid4pay.com
Content-Type: application/x-www-form-urlencoded
token=<AT or RT>
&token_type_hint=refresh_token
&client_id=<agent_client_id>
&client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer
&client_assertion=<private_key_jwt>
200 OK
(empty body, per RFC 7009)Three auth modes
| Mode | Header / parameter | Used by |
|---|---|---|
| Client-owned | client_assertion=<private_key_jwt> | The agent revokes its own tokens. |
| Principal-owned | Wallet Portal session cookie | The principal revokes an agent's tokens from the wallet UI. |
| Admin | X-Internal-Key: <hmac> | Operator-initiated revocation (e.g. response to a compromised key). |
Cascade semantics
- Revoking an AT: the AT's
jtiis added to the revocation set; subsequent presentations are rejected. - Revoking an RT: the RT family is marked revoked; every AT issued from the family is killed; the underlying mandate is killed.
- Revoking a mandate: every RT family that depends on the mandate is killed; every AT in those
families is killed; the mandate's
credentialStatusbit is flipped (see W3C VC Status List).
Worked example: agent revokes its own token
curl -sS https://as.oid4pay.com/oauth/revoke \
-d token=$RT \
-d token_type_hint=refresh_token \
-d client_id=$CLIENT_ID \
-d client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer \
--data-urlencode client_assertion=$PKJ
# 200 OK with empty body
# SSF event oid4ac.mandate.revoked emitted to subscribed receiversWorked example: principal revokes via wallet
// Inside wallet.oid4pay.com:
await fetch("https://as.oid4pay.com/oauth/revoke", {
method: "POST",
headers: { "content-type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
token: mandateRt,
token_type_hint: "refresh_token",
}),
credentials: "include",
});RFC 7009 silence on unknown tokens
RFC 7009 §2.2 requires the revocation endpoint to return 200 even when the token is unknown (otherwise it leaks information about which tokens exist). OID4Pay's AS conforms: a syntactically valid request always returns 200.