OAuth 2.0 refresh-token rotation reuse-detection limits
0 reputation · 30 Jul 2023, 01:15 UTC
0 reputation · 30 Jul 2023, 01:15 UTC
RFC 6749 makes refresh-token rotation optional: an authorization server MAY issue a new refresh token, and the client MUST discard the old value when one arrives. The draft OAuth 2.1 revision recommends rotation with reuse detection for public clients, but as a draft it does not impose a binding requirement on deployed servers.
Because the core framework does not define a required response to replaying a rotated refresh token, the authorization server chooses whether to invalidate only the replayed token or revoke the entire token family. A client cannot infer this policy from the specification, and rotation alone does not bind the access token to the client.
For a public client using PKCE against an authorization server with undocumented reuse handling, what reuse-detection behavior should the client assume when a previous refresh token is replayed?
If the server revokes the whole grant after detecting reuse, should the client interpret a later invalid_grant error as a reason to restart the authorization-code flow instead of retrying the refresh grant?
Should a client that cannot determine the server's reuse-detection policy default to treating any invalid_grant on a rotated token as a full grant revocation?
33775 reputation · 30 Jul 2023, 11:10 UTC
When you have a public client using PKCE and the server’s reuse policy is not documented, treat a replay of a rotated refresh token as a full grant revocation. If you receive invalid_grant after a rotated token, stop retrying that token and restart the authorization‑code flow. Only if you can confirm the server revokes just the replayed token and you still hold a newer replacement token can you safely retry with the replacement.
invalid_grant responses can look like abuse and may trigger rate‑limiting or account lockout.invalid_grant from a refresh request, assume the whole grant is revoked. Do not retry the same refresh token.invalid_grant, use it; otherwise proceed to step 4.If you learn that the server revokes only the replayed token and you still have a valid replacement token, you may safely retry the refresh with the replacement. This requires explicit documentation or a server‑side introspection response that marks the replacement as active.
Does the server revoke only the replayed refresh token, or does it revoke the entire refresh‑token family? Knowing the answer lets you decide whether to restart the flow or simply use the replacement token.
Assume full grant revocation on replayed rotated tokens unless you have documented evidence to the contrary. Treat invalid_grant as a signal to re‑authorize rather than to retry the same refresh token.
Use comments to ask for clarification. Post a solution as an answer.
33,775 reputation · 30 Jul 2023, 05:43 UTC
RFC 6749 defines invalid_grant broadly, covering expired, revoked, malformed, or mismatched authorization codes, grants, and refresh tokens. The specification does not reserve a distinct error code for reuse detection, so a client cannot tell from the error alone whether the server rejected only the replayed token or revoked the entire token family.
Unless the server documents a specific error_description or extension, the conservative client behavior is to treat the failure as terminal for that grant: stop retrying the refresh grant and restart the authorization-code flow. This avoids unsafe retries against a revoked family, though it may occasionally trigger unnecessary re-authentication if the server returns invalid_grant for ordinary expiration.
To confirm the actual policy, replay a rotated token in a test environment and observe whether subsequent refresh attempts also fail, or use token introspection if the endpoint is available.