invalid_grant
security
auth_error
ai_generated
true
OAuth2 refresh token replay detected: same refresh token used more than once
ID: security/oauth2-token-replay-via-refresh-token
80%Fix Rate
85%Confidence
1Evidence
2023-05-15First Seen
Version Compatibility
| Version | Status | Introduced | Deprecated | Notes |
|---|---|---|---|---|
| OAuth 2.0 RFC 6749 | active | — | — | — |
| Spring Security OAuth2 2.5.x | active | — | — | — |
| Keycloak 21.0.x | active | — | — | — |
| Auth0 Node.js SDK 2.0.0 | active | — | — | — |
| Okta .NET SDK 3.0.0 | active | — | — | — |
Root Cause
OAuth2 refresh token is not rotated after each use, allowing an attacker who steals the token to reuse it indefinitely and obtain new access tokens.
generic中文
OAuth2 刷新令牌在每次使用后未轮换,导致窃取令牌的攻击者可以无限重放以获取新的访问令牌。
Official Documentation
https://datatracker.ietf.org/doc/html/rfc6749#section-1.5Workarounds
-
90% success Implement refresh token rotation: issue a new refresh token with each access token refresh and invalidate the old one. Example: In Spring Security OAuth2, set `refreshTokenRotationEnabled=true` in authorization server config.
Implement refresh token rotation: issue a new refresh token with each access token refresh and invalidate the old one. Example: In Spring Security OAuth2, set `refreshTokenRotationEnabled=true` in authorization server config.
-
85% success Use refresh token expiration with a short TTL (e.g., 15 minutes) combined with rotation, and require re-authentication after expiry.
Use refresh token expiration with a short TTL (e.g., 15 minutes) combined with rotation, and require re-authentication after expiry.
-
75% success Add a client-side nonce or binding to refresh token to tie it to a specific device or session, preventing cross-device replay.
Add a client-side nonce or binding to refresh token to tie it to a specific device or session, preventing cross-device replay.
中文步骤
Implement refresh token rotation: issue a new refresh token with each access token refresh and invalidate the old one. Example: In Spring Security OAuth2, set `refreshTokenRotationEnabled=true` in authorization server config.
Use refresh token expiration with a short TTL (e.g., 15 minutes) combined with rotation, and require re-authentication after expiry.
Add a client-side nonce or binding to refresh token to tie it to a specific device or session, preventing cross-device replay.
Dead Ends
Common approaches that don't work:
-
95% fail
Longer expiration gives attackers more time to exploit stolen tokens; does not address the fundamental replay vulnerability.
-
70% fail
Blacklists are hard to maintain in distributed systems and require real-time synchronization; attackers can still replay before blacklisting.
-
85% fail
Rate limiting may block legitimate users and does not prevent a single replay attack; attacker can still use the token once before rate limit kicks in.