invalid_grant
security
protocol_error
ai_generated
true
OAuth2刷新令牌轮换失败:检测到刷新令牌重用
OAuth2 refresh token rotation failed: refresh token reuse detected
ID: security/oauth2-refresh-token-rotation-failure
85%修复率
87%置信度
1证据数
2024-04-01首次发现
版本兼容性
| 版本 | 状态 | 引入 | 弃用 | 备注 |
|---|---|---|---|---|
| OAuth 2.0 RFC 6749 | active | — | — | — |
| Auth0 OIDC 2.0 | active | — | — | — |
| Keycloak 21.0.0 | active | — | — | — |
| Microsoft Identity Platform v2.0 | active | — | — | — |
根因分析
OAuth2授权服务器检测到之前使用过的刷新令牌被重用,表明可能存在令牌窃取;服务器撤销了发给该客户端的所有令牌。
English
The OAuth2 authorization server detected that a previously used refresh token was reused, indicating potential token theft; the server revokes all tokens issued to the client in response.
官方文档
https://datatracker.ietf.org/doc/html/rfc6749#section-6解决方案
-
Implement refresh token rotation correctly: after each successful refresh, discard the old refresh token and store the new one. Example in a Node.js OAuth2 client: async function refreshAccessToken(refreshToken) { const response = await fetch('https://auth.example.com/token', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: new URLSearchParams({ grant_type: 'refresh_token', refresh_token: refreshToken, client_id: 'your-client-id', client_secret: 'your-client-secret' }) }); const data = await response.json(); if (data.refresh_token) { // Securely store the new refresh token await storeRefreshToken(data.refresh_token); } return data.access_token; } -
Use short-lived refresh tokens and implement a fallback to the authorization code flow if refresh fails. For example, in Auth0: const client = new OAuth2Client({ clientId: 'your-client-id', authorizationUri: 'https://auth.example.com/authorize', tokenUri: 'https://auth.example.com/token', redirectUri: 'https://app.example.com/callback', usePKCE: true, refreshTokenRotation: true }); try { const token = await client.refreshToken(oldRefreshToken); } catch (error) { if (error.message.includes('refresh token reuse')) { // Redirect user to login again window.location.href = '/login'; } } -
If using Keycloak, configure refresh token revocation on reuse in the realm settings: Keycloak Admin Console -> Realm Settings -> Tokens -> 'Revoke Refresh Token' = ON This ensures that any reuse triggers immediate revocation.
无效尝试
常见但无效的做法:
-
Ignore the error and retry the same refresh token
100% 失败
Once the server detects reuse, it revokes all tokens; retrying the same token will always fail.
-
Use a new refresh token without going through the full authorization flow
90% 失败
The server expects the client to obtain a new refresh token via a fresh authorization code or client credentials flow; there is no shortcut.
-
Store multiple refresh tokens and rotate among them
95% 失败
The server tracks reuse per token; any reused token will trigger revocation, regardless of rotation strategy.