OAuth2 refresh token reuse detection failure allows token theft to go unnoticed
ID: security/oauth2-refresh-token-reuse-detection-failure
Version Compatibility
| Version | Status | Introduced | Deprecated | Notes |
|---|---|---|---|---|
| OAuth2 2.0 | active | — | — | — |
| Spring Security 6.2.0 | active | — | — | — |
| Keycloak 23.0.0 | active | — | — | — |
| Auth0 Node.js SDK 2.45.0 | active | — | — | — |
Root Cause
The authorization server does not implement refresh token rotation or reuse detection, so if an attacker steals a refresh token and uses it, the legitimate user's token remains valid, allowing the attacker to continue obtaining new access tokens indefinitely.
generic中文
授权服务器未实现刷新令牌轮换或重用检测,因此如果攻击者窃取刷新令牌并使用它,合法用户的令牌仍然有效,允许攻击者无限期地继续获取新的访问令牌。
Official Documentation
https://datatracker.ietf.org/doc/html/rfc6749#section-10.4Workarounds
-
92% success Implement refresh token rotation: issue a new refresh token each time a refresh token is used, and invalidate the old one. In Spring Security, configure `refreshTokenRotationStrategy` to `ROTATE` in the authorization server configuration. Example: `@Bean public OAuth2AuthorizationServerConfigurer authorizationServerConfigurer() { return new OAuth2AuthorizationServerConfigurer() .refreshTokenRotationStrategy(RefreshTokenRotationStrategy.ROTATE); }`.
Implement refresh token rotation: issue a new refresh token each time a refresh token is used, and invalidate the old one. In Spring Security, configure `refreshTokenRotationStrategy` to `ROTATE` in the authorization server configuration. Example: `@Bean public OAuth2AuthorizationServerConfigurer authorizationServerConfigurer() { return new OAuth2AuthorizationServerConfigurer() .refreshTokenRotationStrategy(RefreshTokenRotationStrategy.ROTATE); }`. -
88% success Implement refresh token reuse detection: if a refresh token is used more than once, revoke all tokens for that client and user. In Keycloak, enable "Revoke Refresh Token" in the client settings under "Advanced Settings". This invalidates the token family upon reuse.
Implement refresh token reuse detection: if a refresh token is used more than once, revoke all tokens for that client and user. In Keycloak, enable "Revoke Refresh Token" in the client settings under "Advanced Settings". This invalidates the token family upon reuse.
-
90% success Use a combination of rotation and reuse detection. Store the last used refresh token in a database and compare on each request. If the token has been used before, revoke all tokens and alert the user. Example pseudocode: `if (token in usedTokens) { revokeAllTokens(user); alert("Security breach detected"); } else { usedTokens.add(token); issueNewToken(); }`.
Use a combination of rotation and reuse detection. Store the last used refresh token in a database and compare on each request. If the token has been used before, revoke all tokens and alert the user. Example pseudocode: `if (token in usedTokens) { revokeAllTokens(user); alert("Security breach detected"); } else { usedTokens.add(token); issueNewToken(); }`.
中文步骤
实现刷新令牌轮换:每次使用刷新令牌时发放新的刷新令牌,并使旧的失效。在 Spring Security 中,在授权服务器配置中将 `refreshTokenRotationStrategy` 设置为 `ROTATE`。示例:`@Bean public OAuth2AuthorizationServerConfigurer authorizationServerConfigurer() { return new OAuth2AuthorizationServerConfigurer() .refreshTokenRotationStrategy(RefreshTokenRotationStrategy.ROTATE); }`。实现刷新令牌重用检测:如果刷新令牌被多次使用,则撤销该客户端和用户的所有令牌。在 Keycloak 中,在客户端设置的“高级设置”下启用“撤销刷新令牌”。这将在重用时使令牌系列无效。
结合使用轮换和重用检测。将上次使用的刷新令牌存储在数据库中,并在每次请求时进行比较。如果令牌之前已被使用,则撤销所有令牌并提醒用户。示例伪代码:`if (token in usedTokens) { revokeAllTokens(user); alert("检测到安全漏洞"); } else { usedTokens.add(token); issueNewToken(); }`。
Dead Ends
Common approaches that don't work:
-
Set a very short expiration time for refresh tokens (e.g., 5 minutes)
50% fail
Short expiration reduces the window of opportunity but does not prevent reuse. An attacker can still use the token within that window, and the legitimate user's session is interrupted.
-
Use IP-based validation to detect unusual refresh token usage
60% fail
IP addresses can be spoofed or changed (e.g., via VPN), and legitimate users may have dynamic IPs, leading to false positives. This is not a reliable security measure.
-
Block the user account after a single refresh token use
80% fail
This would break legitimate usage where users refresh tokens normally. It also does not distinguish between the legitimate user and the attacker.