Appearance
Logout Flow
This page documents the logout flow in GrydAuth, which properly invalidates tokens and cleans up session data.
Overview
Logout in GrydAuth is more than just clearing client-side tokens. It involves server-side token invalidation to prevent unauthorized use of stolen tokens and maintains security audit trails.
Logout Types
| Type | Description | Use Case |
|---|---|---|
| Single Logout | Invalidates current session only | User clicks logout button |
| Global Logout | Invalidates all sessions | Password change, security concern |
| Admin Logout | Force logout specific user | Security incident response |
Single Logout Sequence Diagram
100% 💡 Use Ctrl + Scroll para zoom | Arraste para navegar
Global Logout (All Sessions)
When a user wants to log out from all devices or after a password change:
100% 💡 Use Ctrl + Scroll para zoom | Arraste para navegar
Admin Force Logout
Administrators can force logout specific users:
100% 💡 Use Ctrl + Scroll para zoom | Arraste para navegar
Step-by-Step Explanation
Single Logout
1. Send Logout Request
http
POST /api/auth/logout
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...
Content-Type: application/json
{
"refreshToken": "550e8400-e29b-41d4-a716-446655440000"
}2. Invalidate Refresh Token
The refresh token is deleted from Redis, preventing future token refresh.
3. Blacklist Access Token (Optional)
For immediate invalidation before natural expiration:
csharp
var tokenId = jwt.Claims.First(c => c.Type == "jti").Value;
var expiration = jwt.ValidTo - DateTime.UtcNow;
await _cache.SetAsync(
$"blacklist:{tokenId}",
true,
expiration
);4. Audit Logging
All logout events are recorded for security auditing.
5. Client Cleanup
typescript
async function logout(): Promise<void> {
const refreshToken = authStore.getRefreshToken();
try {
await authApi.logout({ refreshToken });
} catch (error) {
// Log error but continue with client cleanup
console.error('Server logout failed:', error);
} finally {
// Always clear client state
authStore.clearTokens();
authStore.clearUser();
router.push('/login');
}
}Global Logout
Token Version Mechanism
Instead of tracking all active tokens, GrydAuth uses a token version:
csharp
public class User
{
public int TokenVersion { get; private set; }
public void InvalidateAllTokens()
{
TokenVersion++;
}
}JWT tokens include the version:
json
{
"sub": "user-id",
"token_version": 4,
...
}On validation:
csharp
if (tokenVersion != user.TokenVersion)
{
throw new SecurityTokenException("Token invalidated");
}Admin Force Logout
Used for:
- Security incident response
- Employee termination
- Suspicious activity detection
- Compliance requirements
Token Blacklist Strategy
100% 💡 Use Ctrl + Scroll para zoom | Arraste para navegar
Recommended: Hybrid Approach
csharp
public class LogoutOptions
{
// Always invalidate refresh token
public bool InvalidateRefreshToken { get; set; } = true;
// Blacklist access token for immediate invalidation
public bool BlacklistAccessToken { get; set; } = true;
// For short-lived tokens (< 5 min), skip blacklist
public TimeSpan BlacklistThreshold { get; set; } = TimeSpan.FromMinutes(5);
}Error Scenarios
| Error | HTTP Status | Cause | Action |
|---|---|---|---|
| Invalid token | 401 | Already logged out or expired | Proceed to login |
| Missing refresh token | 400 | Client didn't send refresh token | Best effort logout |
| Server error | 500 | Cache or DB failure | Clear client state anyway |
Security Best Practices
1. Always Invalidate Server-Side
typescript
// ❌ Bad - Only client-side cleanup
function logout() {
localStorage.removeItem('token');
router.push('/login');
}
// ✅ Good - Server-side + client-side
async function logout() {
await authApi.logout({ refreshToken });
authStore.clearAll();
router.push('/login');
}2. Handle Logout Failures Gracefully
typescript
async function logout(): Promise<void> {
try {
await authApi.logout({ refreshToken });
} catch (error) {
// Server logout failed - token might already be invalid
console.warn('Server logout failed:', error);
}
// Always clear client state
authStore.clearAll();
}3. Clear All Sensitive Data
typescript
function clearAll(): void {
// Clear tokens
this.accessToken = null;
this.refreshToken = null;
// Clear user data
this.user = null;
this.tenant = null;
this.permissions = [];
// Clear any cached data
queryClient.clear();
// Clear cookies if used
document.cookie = 'session=; expires=Thu, 01 Jan 1970';
}4. Implement Logout on Token Expiry
typescript
// When refresh token fails, trigger logout
axios.interceptors.response.use(
response => response,
async error => {
if (error.response?.status === 401) {
const errorCode = error.response.data?.error;
if (['token_revoked', 'session_terminated'].includes(errorCode)) {
// Force logout - don't try to refresh
await logout();
return Promise.reject(error);
}
}
return Promise.reject(error);
}
);Configuration
json
{
"LogoutSettings": {
"BlacklistAccessTokens": true,
"BlacklistThresholdMinutes": 5,
"SendLogoutNotification": true,
"EnableGlobalLogout": true,
"EnableAdminForceLogout": true
}
}Audit Log Example
json
{
"eventType": "UserLogout",
"timestamp": "2026-02-02T14:30:00Z",
"userId": "550e8400-e29b-41d4-a716-446655440000",
"tenantId": "tenant-123",
"details": {
"logoutType": "single",
"ipAddress": "192.168.1.100",
"userAgent": "Mozilla/5.0...",
"refreshTokenInvalidated": true,
"accessTokenBlacklisted": true
}
}Related Flows
- Login Flow - Initial authentication
- Refresh Token - Token renewal
- First Login - Password change required