# OAuth2 refresh token rotation failure allows token theft

- **ID:** `security/oauth2-refresh-token-rotation-failure-allows-token-theft`
- **Domain:** security
- **Category:** auth_error
- **Error Code:** `OAUTH2_REFRESH_TOKEN_ROTATION_FAILURE`
- **Verification:** ai_generated
- **Fix Rate:** 87%

## Root Cause

When refresh token rotation is not implemented, a stolen refresh token remains valid indefinitely, allowing an attacker to obtain new access tokens without detection.

## Version Compatibility

| Version | Status | Introduced | Deprecated |
|---------|--------|------------|------------|
| OAuth2.0 | active | — | — |
| Spring Security 5.6+ | active | — | — |
| Keycloak 21.0.0 | active | — | — |
| Okta 2023.07.0 | active | — | — |

## Workarounds

1. **Implement refresh token rotation: issue a new refresh token each time the old one is used, and invalidate the old token. Example in Spring Security: configure oauth2Client with refreshTokenRotationEnabled(true).** (90% success)
   ```
   Implement refresh token rotation: issue a new refresh token each time the old one is used, and invalidate the old token. Example in Spring Security: configure oauth2Client with refreshTokenRotationEnabled(true).
   ```
2. **Implement refresh token reuse detection: if a revoked refresh token is used, revoke all tokens for that user and alert. Example in Keycloak: enable 'Revoke Refresh Token' in client settings.** (85% success)
   ```
   Implement refresh token reuse detection: if a revoked refresh token is used, revoke all tokens for that user and alert. Example in Keycloak: enable 'Revoke Refresh Token' in client settings.
   ```
3. **Set a maximum refresh token lifetime (e.g., 24 hours) and force re-authentication after expiry, combined with rotation.** (80% success)
   ```
   Set a maximum refresh token lifetime (e.g., 24 hours) and force re-authentication after expiry, combined with rotation.
   ```

## Dead Ends

- **** — Setting a short access token lifetime (e.g., 5 minutes) does not protect against refresh token theft because the attacker can still use the refresh token to get new tokens repeatedly. (70% fail)
- **** — Revoking all tokens on logout is insufficient if the attacker already has the refresh token and uses it before logout. (60% fail)
- **** — Using a single refresh token with a long lifetime is the default in many OAuth2 implementations, which directly enables this vulnerability. (50% fail)
