Authentication Flow
This document describes the complete authentication flow architecture implemented in the CIVITAS Core v2 platform using modern OAuth2/OIDC standards with Keycloak as the identity provider.
Overview
The authentication system implements a secure OAuth2/OIDC flow with Keycloak integration, JWT-based session management, and comprehensive route protection. The architecture follows the Backend-For-Frontend (BFF) pattern with security-by-design principles, ensuring that sensitive tokens never reach the client-side while providing a seamless user experience across the platform.
JWT Token Architecture (Backend-For-Frontend Pattern)
The system employs a secure Backend-For-Frontend (BFF) architecture with two distinct types of JWT tokens:
- Keycloak JWT Access Token: The actual access token issued by Keycloak, used for authenticating API calls to backend services. This JWT contains user claims and permissions for resource access. These tokens are never exposed to client-side JavaScript.
- NextAuth Session JWT: A separate JWT created by NextAuth that wraps the Keycloak tokens (access_token, refresh_token) plus session metadata. This JWT is stored in the HTTP-only session cookie and acts as an opaque session identifier from the client's perspective.
Security Model
Client-Side Access:
- Client receives session data (user info, authentication status) but no tokens (access token or refresh token)
- Session cookie acts as an opaque identifier - client cannot decrypt or access tokens within it
- All token operations happen exclusively server-side
Server-Side Access:
- Server-side code can access tokens through NextAuth's JWT callback system
- API routes and server components can retrieve tokens for backend authentication
- Token refresh happens automatically server-side without client involvement
When making authenticated API calls to backend services, tokens are accessed server-side only and never transmitted to the client.
Authentication Flow Sequence Diagram
Flow Description
1. Initial Access Attempt
When a user attempts to access a protected resource, the platform's middleware layer intercepts the request and validates the user's authentication status. If no valid session exists, the user is automatically redirected to the login interface, ensuring that protected resources remain secure while providing a smooth user experience.
2. Login Initiation
The login interface presents users with authentication options, prominently featuring Keycloak integration. This centralized approach ensures consistent authentication across all platform components and leverages identity management capabilities.
3. OAuth2/OIDC Flow
The platform implements the standard OAuth2 Authorization Code flow with OIDC extensions, providing robust security through:
- Authorization Code Exchange: Prevents token exposure in browser history
- State Parameter Validation: Protects against CSRF attacks
- PKCE Support: Enhances security for public clients
- Scope-based Access Control: Enables fine-grained permission management
4. Token Exchange and Management
Upon successful authentication, the system securely exchanges the authorization code for access tokens, refresh tokens, and identity tokens. This server-to-server communication ensures that sensitive credentials never traverse the client-side environment.
5. Session Architecture
The platform employs a hybrid session management approach:
- JWT-based Storage: Enables stateless authentication and horizontal scaling
- Secure Cookie Delivery: HTTP-only, secure cookies prevent XSS attacks
- Token Encapsulation: NextAuth embeds access and refresh tokens in its own signed JWT payload, which is then stored in an HTTP-only cookie
Token Refresh Mechanism
The system uses an event-based token refresh approach where tokens are refreshed when the jwt() callback is invoked during requests. When an access token expires, the JWT callback triggers a refresh request to Keycloak's token endpoint. After successful token refresh, NextAuth re-issues the session cookie with the updated token to maintain session continuity. If the refresh fails, the session receives a "RefreshTokenError" and the user must re-authenticate.
Automatic Session Refresh
The platform implements a proactive session refresh system to prevent unexpected logouts:
Proactive Refresh: Client-side session provider configured with 4-minute intervals automatically refreshes tokens before expiration, ensuring seamless user experience.
Activity-Based Refresh: User interaction monitoring detects activity (mouse, keyboard, scroll, touch) and triggers session refresh when users are active, resetting refresh timers based on activity patterns.
Retry Logic: Token refresh mechanism includes retry system with maximum 3 attempts and automatic counter reset on successful refresh, preventing infinite loops while ensuring reliability.
Implementation Features:
- Invisible session management component that activates activity detection across the application
- Activity detection with 2-minute cooldown between refresh attempts
- Enhanced token callback with retry counter and attempt limits
This ensures users remain logged in as long as they stay active, with tokens refreshed proactively before expiration.
6. Route Protection and Access Control
A comprehensive middleware system ensures that:
- All protected routes require valid authentication
- Public endpoints remain accessible without authentication
- Session validation occurs transparently for each request
- Invalid or expired sessions trigger automatic re-authentication
7. Ongoing Session Management
Authenticated users enjoy seamless access to protected resources through persistent session cookies. The system validates sessions on each request while maintaining optimal performance through efficient token validation mechanisms.
Logout Flow
The platform implements a secure dual logout mechanism that terminates both the NextAuth session and the Keycloak session simultaneously, preventing silent re-authentication and ensuring complete session cleanup.
Logout Sequence Diagram
Implementation Details
NextAuth Events Callback: The logout process uses NextAuth's signOut event handler in auth.config.ts to automatically trigger Keycloak logout when the local session is destroyed.
ID Token Hint: The stored ID token (id_token_hint) is sent to Keycloak's logout endpoint, enabling automatic session termination without user confirmation dialogs.
Simultaneous Execution: Both logout processes happen in parallel - NextAuth destroys the local session while the event handler terminates the Keycloak session server-side.
Security Aspects
- Complete Session Termination: Both application and identity provider sessions are properly destroyed
- Prevention of Silent Re-authentication: Keycloak cannot automatically log users back in on subsequent authentication attempts
- Seamless User Experience: No logout confirmation pages or intermediate redirects
- Server-side Security: Logout requests are made server-to-server, never exposing tokens to the client
Key Components
Middleware Layer
The middleware component intercepts all requests and applies authentication policies. It handles route protection by distinguishing between public paths (login, API authentication endpoints) and protected routes that require valid user sessions. The middleware applies authentication to all routes except API endpoints, static assets, images, and files with extensions.
Authorization Logic
The system implements authorization checks that verify user authentication status and determine access permissions. When users are not authenticated, they are redirected to the login interface, while authenticated users can access protected resources.
JWT Token Management
The platform uses JWT callbacks to handle token lifecycle:
- Stores access tokens, refresh tokens, ID tokens, and expiration information within JWT payloads
- Manages token persistence and retrieval for session validation
- Handles token-based authentication across requests
- ID tokens enable seamless logout by providing
id_token_hintto Keycloak - Session maximum age: 30 days
- Token expiration check includes 60-second buffer before actual expiry
- Access tokens are refreshed automatically when expired