Appearance
Refresh Token Flow
This page documents the token refresh flow in GrydAuth, which allows users to obtain new access tokens without re-entering their credentials.
Overview
Access tokens in GrydAuth are short-lived (default: 1 hour) for security purposes. When an access token expires, the client can use the refresh token to obtain a new access token without requiring the user to log in again.
Token Lifetimes
| Token Type | Default Lifetime | Purpose |
|---|---|---|
| Access Token | 1 hour | API authentication |
| Refresh Token | 7 days | Obtain new access tokens |
| Sliding Expiration | Optional | Extends refresh token on use |
Sequence Diagram
100% 💡 Use Ctrl + Scroll para zoom | Arraste para navegar
Step-by-Step Explanation
Phase 1: Access Token Expiration
When the access token expires, API requests return 401 Unauthorized with error: "token_expired". The client should detect this and initiate the refresh flow.
Phase 2: Token Refresh
2.1 Send Refresh Request
json
POST /api/auth/refresh
{
"refreshToken": "550e8400-e29b-41d4-a716-446655440000"
}2.2 Validate Refresh Token
The refresh token is validated against Redis cache:
csharp
var tokenData = await _cache.GetAsync<RefreshTokenData>(refreshToken);
if (tokenData == null)
return Result.Failure("Invalid refresh token");2.3 Validate User Status
The system ensures:
- User still exists
- User is active (
IsActive = true) - User is not locked out
2.4 Token Version Check
Token version prevents use of old tokens after:
- Password change
- Admin-forced logout
- Security incident response
csharp
if (tokenData.TokenVersion != user.TokenVersion)
{
await _cache.DeleteAsync(refreshToken);
return Result.Failure("Token invalidated");
}2.5 Tenant Validation
Ensures the user still has access to the tenant from the original token.
2.6 Refresh Roles & Permissions
Important: The new access token contains the current roles and permissions, not the cached ones. This ensures permission changes take effect immediately.
2.7 Token Rotation
For security, GrydAuth implements refresh token rotation:
- Old refresh token is deleted
- New refresh token is generated
- Client must use new refresh token for next refresh
This limits the damage if a refresh token is compromised.
Phase 3: Resume Operations
Client stores the new tokens and continues making API requests.
Automatic Token Refresh
Client-Side Implementation
typescript
// Axios interceptor for automatic refresh
axios.interceptors.response.use(
(response) => response,
async (error) => {
const originalRequest = error.config;
if (error.response?.status === 401 &&
error.response?.data?.error === 'token_expired' &&
!originalRequest._retry) {
originalRequest._retry = true;
try {
const { accessToken, refreshToken } = await authService.refresh();
authStore.setTokens(accessToken, refreshToken);
originalRequest.headers.Authorization = `Bearer ${accessToken}`;
return axios(originalRequest);
} catch (refreshError) {
// Refresh failed - redirect to login
authStore.clearTokens();
router.push('/login');
return Promise.reject(refreshError);
}
}
return Promise.reject(error);
}
);Token Refresh Service
typescript
class AuthService {
private refreshPromise: Promise<TokenResponse> | null = null;
async refresh(): Promise<TokenResponse> {
// Prevent multiple simultaneous refresh requests
if (this.refreshPromise) {
return this.refreshPromise;
}
this.refreshPromise = this.doRefresh();
try {
return await this.refreshPromise;
} finally {
this.refreshPromise = null;
}
}
private async doRefresh(): Promise<TokenResponse> {
const refreshToken = authStore.getRefreshToken();
const response = await api.post('/auth/refresh', { refreshToken });
return response.data;
}
}Sliding Expiration
When enabled, refresh token expiration is extended on each use:
100% 💡 Use Ctrl + Scroll para zoom | Arraste para navegar
Error Scenarios
| Error | HTTP Status | Cause | Client Action |
|---|---|---|---|
| Invalid refresh token | 401 | Token not found in cache | Redirect to login |
| Token expired | 401 | Refresh token TTL exceeded | Redirect to login |
| Token revoked | 401 | Password changed or admin action | Redirect to login |
| User inactive | 401 | Account deactivated | Show account disabled message |
| Tenant access revoked | 403 | Removed from tenant | Redirect to tenant selection |
Security Considerations
Refresh Token Storage
| Platform | Recommended Storage |
|---|---|
| Web (SPA) | HttpOnly cookie or memory |
| Mobile | Secure storage (Keychain/Keystore) |
| Desktop | OS credential manager |
Never Store in localStorage
Refresh tokens should never be stored in localStorage due to XSS vulnerability.
Token Rotation Benefits
- Limits exposure window - Stolen tokens become invalid after one use
- Detects theft - If legitimate user's refresh fails, theft is detected
- Audit trail - Each rotation is logged for security analysis
Absolute Expiration
Even with sliding expiration, consider an absolute maximum lifetime:
csharp
public class RefreshTokenOptions
{
public TimeSpan SlidingExpiration { get; set; } = TimeSpan.FromDays(7);
public TimeSpan AbsoluteExpiration { get; set; } = TimeSpan.FromDays(30);
}Configuration
json
{
"JwtSettings": {
"AccessTokenExpirationMinutes": 60,
"RefreshTokenExpirationDays": 7,
"EnableSlidingExpiration": true,
"EnableTokenRotation": true
}
}Related Flows
- Login Flow - Initial authentication
- Logout Flow - Token invalidation
- Switch Tenant - Changing tenant context