Token endpoint
Each form field may appear once. Unknown fields are rejected with
invalid_request.
Exchange the authorization code
Token response
Every grant returns the same shape.
Store the refresh token per user on your backend. Do not persist access tokens beyond their lifetime.
Refresh the access token
refresh_token.
Rotation and replay
- Every refresh returns a new refresh token and invalidates the one you sent.
- Presenting an already-used refresh token is treated as replay. OFAuth revokes the whole authorization that token belongs to and sends
authorization.revokedwithreason: "refresh_token_replay". Other users are not affected. - After a replay, every refresh for that authorization fails with
invalid_grant. The user must authorize again. - Serialize refreshes per session. Two concurrent refreshes with the same token look like replay.
Sessions
Each successful code exchange starts a session: a refresh token and the tokens rotated from it. Running authorization again for the same user starts another session in the same authorization. If you lose a refresh token, send the user through authorization again; they see the accounts and scopes they already approved.Revoke
client_secret_basic and send a form body.
200 with an empty body, including for tokens that are already invalid.
Revoke ends the session the token belongs to. Other sessions of the same authorization keep working. Revoking the last active session ends the authorization and sends authorization.revoked with reason: "oauth_revocation". The user must then authorize again before you can call Access for them.
To remove one account but keep the rest of the authorization, use DELETE /v3/linked-accounts/{id}.
Discovery
https://auth.ofauth.com/link:
Use it to configure a generic OAuth client library.
Token endpoint errors
Errors follow RFC 6749.
When the integration itself blocks the request, the body also carries
reason and recovery:
reason is one of client_deleted, developer_plan_unavailable, or security_suspended.
Token responses are sent with Cache-Control: no-store.