VOOZH about

URL: https://deepwiki.com/mathsgod/light/5.1-authentication-architecture

⇱ Authentication Architecture | mathsgod/light | DeepWiki


Loading...
Last indexed: 31 January 2026 (cf9511)
Menu

Authentication Architecture

Overview

The Light framework implements a multi-layered JWT-based authentication architecture centered around the Auth\Service class. The system uses dual-token authentication (access/refresh tokens), persistent session tracking via the UserLog table, and security mechanisms including account lockout and token revocation.

Key Architectural Components:

ComponentLocationRole
Auth\Servicesrc/Auth/Service.phpCore authentication service, validates JWT tokens, loads user context
AuthControllersrc/Controller/AuthController.phpGraphQL API for all authentication operations
User Modelsrc/Model/User.phpUser entity with session and permission methods
UserLog TableDatabasePersistent session storage and audit trail
JWT TokensHTTP-only cookiesAccess tokens (15min) and refresh tokens (7 days)
Cache LayerSymfony CacheToken revocation blacklist

This page focuses on the authentication architecture. For specific authentication methods, see:

For authorization, see RBAC System.

Sources: src/App.php38-147 src/Auth/Service.php1-147 src/Controller/AuthController.php1-50


Multi-Layered Architecture

The authentication system operates across multiple architectural layers, from HTTP requests through business logic to data persistence:


Diagram: Multi-Layered Authentication Architecture

The authentication system spans four architectural layers. The HTTP layer handles token storage in cookies. The application layer creates a per-request Auth\Service instance and exposes authentication mutations via AuthController. The business logic layer validates credentials and generates tokens. The data layer persists sessions in UserLog and maintains a token revocation cache.

Sources: src/App.php500-537 src/Auth/Service.php28-80 src/Controller/AuthController.php374-456 src/Model/User.php50-227


Auth\Service - The Core Authentication Component

The Auth\Service class is instantiated for every HTTP request and serves as the central authentication component. It implements GraphQLite's AuthenticationServiceInterface and AuthorizationServiceInterface to integrate with the GraphQL security system.

Initialization and Token Validation


Diagram: Auth\Service Initialization Flow (per request)

Every request creates a new Auth\Service instance that validates the JWT token, checks for revocation, loads the user from the database, and updates session activity. The service is then injected into the DI container and registered with the GraphQL schema factory.

Sources: src/Auth/Service.php28-80 src/App.php526-535

Key Methods and Responsibilities

The Auth\Service class provides the following interface:

MethodReturn TypePurposeUsed By
isLogged()boolChecks if user is authenticated, throws TokenExpiredException if token expiredGraphQLite #[Logged] annotation
getUser()?UserReturns authenticated User object or nullGraphQLite #[InjectUser] annotation
isAllowed(string $right)boolChecks RBAC permission via User->isGranted()GraphQLite #[Right] annotation
getJti()?stringReturns JWT ID for session trackingSession management, logout
isViewAsMode()boolChecks if admin is impersonating another userUI conditional logic
getOrgUser()?UserReturns original admin user in view-as modePermission checks

View-As Mode Implementation: When the JWT payload contains both id (admin user) and view_as (target user), the service loads two user objects:

  • $this->org_user: The original administrator
  • $this->user: The target user being impersonated

This allows administrators to see the application as another user would see it while maintaining their admin permissions for certain operations.

Sources: src/Auth/Service.php82-147

Integration with GraphQLite

The Auth\Service is registered with the GraphQL schema factory as both the authentication and authorization service:


This enables GraphQLite's security annotations to work automatically:

  • #[Logged]: Calls Auth\Service::isLogged(), throws exception if false
  • #[InjectUser]: Calls Auth\Service::getUser(), injects result as parameter
  • #[Right("permission")]: Calls Auth\Service::isAllowed("permission"), checks RBAC

Sources: src/App.php526-535 src/Auth/Service.php100-147


JWT Token System

The framework uses a dual-token architecture with access tokens for API authentication and refresh tokens for obtaining new access tokens without re-authentication.

Token Structure and Lifecycle

Token TypeDefault LifetimePurposeCookie PathClaims
access_token900s (15 min)GraphQL API authentication/iss, jti, iat, exp, role, id, type, view_as?
refresh_token604800s (7 days)Obtaining new access tokens/refresh_tokeniss, jti, iat, exp, id, type

Shared Claims:

  • iss: Issuer, always "light server"
  • jti: JWT ID (UUID v4), uniquely identifies the session
  • iat: Issued at timestamp
  • exp: Expiration timestamp
  • id: User ID (references User.user_id)
  • type: Token type discriminator

Access Token Specific:

  • role: Always "Users" (legacy field)
  • view_as: Optional, present when admin impersonates another user

Both tokens share the same jti value, linking them to a single session record in the UserLog table. This enables session-wide revocation - revoking the jti invalidates both the access and refresh tokens.

Sources: src/App.php636-685 src/Auth/Service.php28-80

Token Generation Process

Token generation occurs in App::userLogin() after successful authentication:


Diagram: Token Generation in App::userLogin()

The App::userLogin() method generates both tokens with a shared jti, creates a session record in UserLog, and sets both cookies. The access token cookie is available site-wide (/), while the refresh token cookie is restricted to the refresh endpoint (/refresh_token) for security.

Sources: src/App.php631-685

Token Refresh Flow

The refresh token enables obtaining a new access token without re-authentication:


Diagram: Token Refresh Flow

The /refresh_token endpoint validates the refresh token, verifies the user still exists, and generates a new access token with the same jti. This maintains session continuity while limiting access token lifetime for security.

Sources: src/App.php877-920

Token Revocation Mechanism

Token revocation is implemented using a cache-based blacklist. When a user logs out or a session is terminated:


Diagram: Token Revocation on Logout

The logout process adds the jti to cache with a TTL equal to the refresh token lifetime, updates the UserLog record with logout_dt, and clears both token cookies.

Revocation Check: Every request validates tokens against the cache in Auth\Service:


This approach provides immediate token invalidation without requiring database queries on every request.

Sources: src/Controller/AuthController.php334-370 src/Auth/Service.php58-60


Session Tracking via UserLog

The UserLog table provides persistent session storage, audit trails, and session management capabilities.

UserLog Schema and Lifecycle


Diagram: UserLog Schema

Each UserLog record represents one authentication attempt or session. The jti field links JWT tokens to database records. The result field distinguishes successful logins ("SUCCESS") from failed attempts ("FAIL"). Active sessions have logout_dt = NULL.

Session Lifecycle:

  1. Login: UserLog record created with login_dt, result="SUCCESS", jti from token
  2. Active: last_access_time updated on each API request via User->saveLastAccessTime()
  3. Logout: logout_dt set to current timestamp
  4. Expired: Sessions older than access_token_expire are considered inactive

Sources: src/App.php650-657 src/Auth/Service.php75-80 src/Controller/AuthController.php343-347

Session Management Methods

The User model provides GraphQL-queryable session management:

getSessions(): array - Lists all active sessions for the user:


The method filters for successful logins with no logout_dt within the token expiration window. It marks the current session (is_current = true) based on matching jti.

revokeSession(jti): bool - Terminates a specific session:


This sets logout_dt for the specified session, preventing it from appearing in active session lists.

saveLastAccessTime(jti): void - Updates last activity timestamp:


Called by Auth\Service on every authenticated request to track session activity.

Sources: src/Model/User.php50-82 src/Model/User.php201-204

Failed Login Tracking

Failed authentication attempts are also recorded in UserLog with result="FAIL":


Failed login records do not have a jti since no token is generated. These records are used by the account lockout mechanism.

Sources: src/Controller/AuthController.php408-415


Account Lockout Mechanism

The framework protects against brute-force password attacks using IP-based account lockout after repeated failed login attempts.

Configuration

Lockout behavior is controlled by two configuration values in the Config table:

KeyTypeDefaultPurpose
auth_lockout_attemptsint5Number of failed attempts before lockout
auth_lockout_durationint15Lockout window in minutes

Implementation

The lockout check occurs before password verification in AuthController::login():


The User::isAuthLocked() method implements the lockout logic:


Diagram: Account Lockout Decision Flow

The method queries UserLog for failed attempts from the same IP within the lockout window. If the failure count meets or exceeds the threshold, the account is locked for that IP address.

Key Implementation Details:


Important Characteristics:

  • IP-based: Lockout applies per IP address, not globally
  • Time-windowed: Only considers failures within the lockout duration
  • Self-healing: Lockout automatically expires after the duration window passes
  • No database flag: Lockout is computed on-demand from UserLog records

Sources: src/Model/User.php206-227 src/Controller/AuthController.php403-405


Additional Security Features

Password Expiration

Password expiration forces users to periodically change their passwords:

Configuration:

  • password_expiration: Enable/disable (boolean)
  • password_expiration_duration: Days until password expires (default: 90)

Enforcement: During login, if enabled and password_dt exceeds the duration, login fails with "password is expired". Users must call changeExpiredPassword() to update.

Sources: src/Controller/AuthController.php446-452 src/Controller/AuthController.php64-102

Rate Limiting on 2FA Setup

The 2FA setup process is rate-limited to prevent abuse:


This limits users to 5 setup attempts per 10 minutes per username.

Sources: src/Controller/AuthController.php31-39


Configuration Reference

Authentication behavior is controlled by configuration values in the Config table and environment variables:

Config Table Values

KeyTypeDefaultPurpose
access_token_expireint900Access token lifetime (seconds)
refresh_token_expireint604800Refresh token lifetime (seconds)
two_factor_authenticationboolfalseEnforce 2FA for all users
auth_lockout_attemptsint5Failed attempts before lockout
auth_lockout_durationint15Lockout duration (minutes)
password_expirationboolfalseEnable password expiration
password_expiration_durationint90Password lifetime (days)
authentication_google_client_idstring-Google OAuth client ID
authentication_microsoft_client_idstring-Microsoft OAuth client ID
authentication_facebook_app_idstring-Facebook OAuth app ID

Environment Variables

VariableRequiredPurpose
JWT_SECRETYesSecret key for JWT signing
COOKIE_DOMAINNoCookie domain (default: current domain)
COOKIE_SECURENoRequire HTTPS for cookies (default: false)
COOKIE_SAMESITENoSameSite cookie attribute (default: "Lax")
COOKIE_PARTITIONEDNoEnable partitioned cookies (default: false)

Sources: src/App.php602-685 src/Controller/AuthController.php


Configuration

Authentication behavior is controlled by several configuration values stored in the Config model:

Configuration KeyTypeDefaultPurpose
access_token_expireint900 (15 min)Access token lifetime in seconds
refresh_token_expireint604800 (7 days)Refresh token lifetime in seconds
two_factor_authenticationboolfalseEnforce 2FA for all users
auth_lockout_attemptsint5Failed attempts before lockout
auth_lockout_durationint15Lockout duration in minutes
password_expirationboolfalseEnable password expiration
password_expiration_durationint90Password lifetime in days
authentication_google_client_idstring-Google OAuth client ID
authentication_microsoft_client_idstring-Microsoft OAuth client ID
authentication_facebook_app_idstring-Facebook OAuth app ID

Additionally, the .env file must contain:

  • JWT_SECRET: Secret key for JWT signing (required)
  • COOKIE_DOMAIN, COOKIE_SECURE, COOKIE_SAMESITE: Cookie configuration

Sources: src/Controller/AuthController.php src/Auth/Service.php