VOOZH about

URL: https://deepwiki.com/mathsgod/light/4.3.1-authcontroller

⇱ AuthController | mathsgod/light | DeepWiki


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

AuthController

Purpose and Scope

The AuthController provides GraphQL mutations for all authentication operations in the Light framework. This includes five authentication methods (password, JWT, OAuth social login, WebAuthn, and 2FA), password management, account linking, and user profile operations.

For the underlying authentication service and JWT validation, see Auth Service. For user session management and account lockout, see User Model and Sessions. For the overall authentication architecture, see Authentication Architecture.

Sources: src/Controller/AuthController.php1-636


Controller Overview

The AuthController class exposes all authentication-related mutations through GraphQLite annotations. It integrates with the Light\App service for session creation, the Auth\Service for JWT handling, and the User model for persistence.

Key Dependencies

DependencyPurpose
Light\AppUser login orchestration, cache, mailer access
Light\Auth\ServiceJWT token extraction and validation
Light\Model\UserUser data persistence and retrieval
Light\Model\UserLogSession and authentication attempt tracking
Light\Security\TwoFactorAuthenticationTOTP code generation and verification
Firebase\JWT\JWTJWT encoding/decoding for password reset
Endroid\QrCodeQR code generation for 2FA setup

Sources: src/Controller/AuthController.php1-27


Authentication Mutations


Diagram: AuthController Mutations and Their Dependencies

Sources: src/Controller/AuthController.php30-636


Password Authentication

login() Mutation

The login() mutation handles username/password authentication with optional 2FA code verification.


Diagram: Login Flow with Account Lockout and 2FA

First User Auto-Creation: If no users exist in the database, the first login attempt automatically creates an admin user with the provided credentials and assigns them to the "Administrators" role.

Account Lockout: The mutation checks User.isAuthLocked() which queries UserLog for failed attempts within the configured lockout window (default: 5 attempts in 15 minutes). See src/Model/User.php206-227 for lockout logic.

Password Verification: Uses PasswordVerify() helper which detects and rejects legacy Unix crypt formats ($5, $6) and only accepts bcrypt hashes.

2FA Enforcement: If global 2FA is enabled via Config::Value("two_factor_authentication"), users without a secret are blocked with error "setup_2fa_required".

Password Expiration: When enabled, checks if the password age exceeds the configured duration (default: 90 days) based on User.password_dt.

Sources: src/Controller/AuthController.php373-456 src/Controller/AuthController.php458-465


Password Reset Flow

The password reset flow uses JWT tokens to secure the reset code transmission.

MutationPurposeAuthentication Required
forgetPassword(username, email)Sends 6-digit code to email, returns JWTNo
forgetPasswordVerifyCode(jwt, code)Validates code without consuming itNo
resetPassword(jwt, password, code)Resets password if code is validNo

JWT Payload Structure:


Rate Limiting: The forgetPasswordVerifyCode() mutation limits each code to 5 verification attempts via Symfony cache with key reset_code_attempt_{code_hash}.

Email Template: The email content is customizable through Config keys:

  • forget_password_email_subject (default: "Password Reset Code")
  • forget_password_email_template (default: "Your password reset code is: {code}")

Sources: src/Controller/AuthController.php596-635 src/Controller/AuthController.php533-552 src/Controller/AuthController.php554-594


changeExpiredPassword() Mutation

Handles password changes when password expiration is enabled. Requires the old password for verification and validates the new password against the system password policy.

Requirements:

  1. Password expiration must be enabled (Config::Value("password_expiration"))
  2. Password must actually be expired (age > configured duration)
  3. Old password must be correct
  4. New password must pass System.isValidPassword() policy check

Sources: src/Controller/AuthController.php63-102


OAuth Social Login

Login Mutations


Diagram: OAuth Login Flow Through External APIs

loginGoogle(credential)

Verifies a Google Sign-In JWT credential using google/apiclient library. Requires authentication_google_client_id in Config.

Flow:

  1. Client obtains JWT credential from Google Sign-In
  2. Server verifies credential with Google_Client::verifyIdToken()
  3. Extracts sub (subject/user ID) from payload
  4. Queries User where google = sub and status = 0
  5. Calls App::userLogin() if user found

Sources: src/Controller/AuthController.php303-330

loginFacebook(access_token)

Verifies a Facebook access token by calling the Graph API. Requires authentication_facebook_app_id in Config.

API Call: GET https://graph.facebook.com/me?fields=id,name,email with Authorization: Bearer {access_token}

Sources: src/Controller/AuthController.php270-300

loginMicrosoft(access_token)

Verifies a Microsoft access token by calling the Microsoft Graph API. Requires authentication_microsoft_client_id in Config.

API Call: GET https://graph.microsoft.com/v1.0/me with Authorization: Bearer {access_token}

Sources: src/Controller/AuthController.php237-267


Account Linking

Account linking mutations require #[Logged] authentication. They associate OAuth provider IDs with the authenticated user's account.

One-to-One Mapping Enforcement

All linking mutations enforce a one-to-one mapping between OAuth IDs and users by first clearing any existing associations:


This prevents multiple accounts from sharing the same OAuth identity.

Linking Mutations

MutationOAuth ProviderField UpdatedAuthentication
registerGoogle(credential)GoogleUser.googleRequired (#[Logged])
registerFacebook(access_token)FacebookUser.facebookRequired (#[Logged])
registerMicrosoft(account_id)MicrosoftUser.microsoftRequired (#[Logged])

Unlinking Mutations

MutationField Cleared
unlinkGoogle()User.google
unlinkFacebook()User.facebook
unlinkMicrosoft()User.microsoft

Sources: src/Controller/AuthController.php121-150 src/Controller/AuthController.php187-234 src/Controller/AuthController.php152-183


Two-Factor Authentication (2FA)

Setup Flow


Diagram: 2FA Setup Sequence

getMy2FA() Mutation

Generates a new TOTP secret and returns setup data for authenticated users.

Returns:

  • secret: Base32-encoded TOTP secret
  • host: Current HTTP host
  • image: Data URI of QR code PNG

OTP URL Format: otpauth://totp/{username}@{host}?secret={secret}

Sources: src/Controller/AuthController.php511-530

updateMy2FA(secret, code) Mutation

Verifies the TOTP code matches the secret and saves it to the user's account. Requires #[Logged] authentication.

Sources: src/Controller/AuthController.php497-508

updateTwoFactorAuthentication(username, password, secret, code)

Alternative 2FA setup mutation that does not require prior authentication. Used during initial setup or when users are locked out.

Rate Limiting: Limited to 5 attempts per username within 10 minutes via cache key two_factor_authentication_setup_{username}.

Validation:

  1. User must exist
  2. User must not already have a secret
  3. Password must be correct
  4. TOTP code must be valid

Sources: src/Controller/AuthController.php30-61

reset2FA(id) Mutation

Administrative mutation to clear a user's 2FA secret. Requires #[Logged] authentication and user.reset2fa permission.

Sources: src/Controller/AuthController.php105-118


Session Management

logout() Mutation

Terminates the current session by revoking the JWT token and clearing cookies.

Operations:

  1. Extracts JTI from Auth\Service::getJti()
  2. Adds JTI to revocation cache: revoked_token_{jti}
  3. Updates UserLog.logout_dt for the JTI
  4. Clears access_token cookie
  5. Clears refresh_token cookie (path: /refresh_token)

Token Revocation: The cache entry expires after the refresh token lifetime, preventing premature garbage collection while the token could still be valid.

Cookie Settings: Respects environment variables:

  • COOKIE_DOMAIN
  • COOKIE_SECURE
  • COOKIE_SAMESITE (default: "Lax")

Sources: src/Controller/AuthController.php333-370


User Profile Operations

getMy() Query

Returns the currently authenticated User object or null if not authenticated. Uses GraphQLite's #[InjectUser] annotation to receive the user from the security context.

Sources: src/Controller/AuthController.php468-472

updateMy(data) Mutation

Updates the authenticated user's profile. Requires #[Logged] authentication.

Input Type: UpdateMyInput (automatically generated from Light\Input\User class)

Implementation:

  1. Filters out null values from input
  2. Binds remaining data to user object via User::bind()
  3. Saves changes

Note: Does not allow updating sensitive fields like password, user_id, or status unless explicitly added to the input type.

Sources: src/Controller/AuthController.php474-490


Security Considerations

Password Storage

Hash TypeStatusError Message
bcrypt ($2y$)SupportedN/A
Unix crypt ($5, $6)Rejected"Password is created with old system..."

The PasswordVerify() helper src/Controller/AuthController.php458-465 explicitly rejects legacy hash formats to prevent security vulnerabilities.

Rate Limiting Summary

OperationLimitDurationCache Key Pattern
2FA Setup (unauthenticated)5 attempts10 minutestwo_factor_authentication_setup_{username}
Password Reset Code Verification5 attempts10 minutesreset_code_attempt_{code_hash}
Login Failures5 attempts15 minutes (configurable)Tracked in UserLog

Token Security

  • JWT Secret: All password reset JWTs use $_ENV['JWT_SECRET'] for signing
  • Code Hashing: Reset codes are hashed with sha256(code + JWT_SECRET) before storage in JWT payload
  • Token Expiration: Password reset JWTs expire after 10 minutes
  • Type Validation: Password reset mutations verify payload.type == "reset_password"

Sources: src/Controller/AuthController.php30-61 src/Controller/AuthController.php533-594


Integration Points

Light\App Dependencies

The controller relies on several Light\App methods injected via #[Autowire]:

MethodPurposeUsed By
userLogin(User)Creates session, sets cookies, logs to UserLogAll login mutations
getCache()Accesses Symfony cache for rate limitinglogout(), 2FA setup, password reset
getMailer()Returns configured PHPMailer instanceforgetPassword()
getRefreshTokenExpire()Gets refresh token TTL for cache expirylogout()
isTwoFactorAuthentication()Checks if global 2FA is enabledlogin()
getAuthService()Gets Auth\Service for JTI extractionVia annotation injection

Sources: src/Controller/AuthController.php30-636

GraphQLite Annotations Used

AnnotationPurposeMethods
#[Mutation]Exposes method as GraphQL mutationAll mutations
#[Query]Exposes method as GraphQL querygetMy()
#[Logged]Requires authenticationAccount linking, 2FA management, profile updates
#[Right]Requires specific permissionreset2FA()
#[Autowire]Injects service dependencyApp, Service injections
#[InjectUser]Injects authenticated userProfile operations
#[UseInputType]Specifies GraphQL input typeupdateMy()

Sources: src/Controller/AuthController.php20-26

Refresh this wiki

On this page