# OAuth2 error: invalid_grant — refresh token expired or revoked

- **ID:** `api/oauth2-invalid-grant-refresh-token-expired`
- **Domain:** api
- **Category:** auth_error
- **Error Code:** `invalid_grant`
- **Verification:** ai_generated
- **Fix Rate:** 85%

## Root Cause

The refresh token used to obtain a new access token has been revoked, expired, or used beyond its rotation limit, causing the authorization server to reject the grant.

## Version Compatibility

| Version | Status | Introduced | Deprecated |
|---------|--------|------------|------------|
| OAuth 2.0 (RFC 6749) | active | — | — |
| Google OAuth 2.0 (2023+) | active | — | — |
| Auth0 OIDC (2024) | active | — | — |

## Workarounds

1. **Implement refresh token rotation: after each successful token refresh, invalidate the old refresh token and issue a new one. In code, use a library like `oauthlib` or `google-auth` that handles rotation automatically. Example: `credentials.refresh(request)` with `google.oauth2.credentials`.** (85% success)
   ```
   Implement refresh token rotation: after each successful token refresh, invalidate the old refresh token and issue a new one. In code, use a library like `oauthlib` or `google-auth` that handles rotation automatically. Example: `credentials.refresh(request)` with `google.oauth2.credentials`.
   ```
2. **Store refresh tokens securely and monitor their expiration. If the error occurs, prompt the user to re-authenticate via the full OAuth flow. Example: catch `RefreshError` and redirect to the authorization endpoint.** (90% success)
   ```
   Store refresh tokens securely and monitor their expiration. If the error occurs, prompt the user to re-authenticate via the full OAuth flow. Example: catch `RefreshError` and redirect to the authorization endpoint.
   ```
3. **Check if the refresh token has been revoked by inspecting the authorization server's token introspection endpoint. Example: `POST /introspect` with `token=<refresh_token>` and `token_type_hint=refresh_token`.** (80% success)
   ```
   Check if the refresh token has been revoked by inspecting the authorization server's token introspection endpoint. Example: `POST /introspect` with `token=<refresh_token>` and `token_type_hint=refresh_token`.
   ```

## Dead Ends

- **** — The token is already expired or revoked; reusing it will still fail. (90% fail)
- **** — The underlying issue (e.g., token rotation limit or revocation) persists, causing the new refresh token to fail again. (70% fail)
- **** — The error is a permanent grant rejection, not a transient network issue; retries will not succeed. (80% fail)
