Skip to content

Login Flow

1. What does this feature do? (High-Level Overview)

Section titled “1. What does this feature do? (High-Level Overview)”

The Login Flow handles user authentication through multiple pathways: standard email/phone login, two-factor authentication verification, and location selection for employees. It supports flexible identifier input (email or phone number) with automatic detection and normalization.

  • All Users: Any registered user (employees or parents) can authenticate using their credentials.
  • Employees: Required to select a location after successful authentication.
  • Parents: Receive immediate access without location selection.
  • No special permissions required for login (public endpoint).
  • Rule 1: User status must be ACTIVE. BLACK_LIST status results in 403 error.
  • Rule 2: Phone numbers are normalized to last 10 digits (US format).
  • Rule 3: Email addresses are case-sensitive (no transformation).
  • Rule 4: If 2FA is enabled for user, authentication requires code verification.
  • Rule 5: Employees must select a location with active access (via user_locations table).
  • Rule 6: Admin View requires access_admin_view global permission.
  • Rule 7: Location must be ACTIVE or STOP status.
  • Rule 8: ALL users (including SUPERADMIN) must have explicit location access - no bypass.

Login Page: /login

Scenario A: Standard Employee Login (Without 2FA)

Section titled “Scenario A: Standard Employee Login (Without 2FA)”

Step 1: Navigate to Login Page

  • Open application at /login
  • Login form displays with identifier and password fields

Step 2: Enter Credentials

Identifier: user@example.com
Password: ********

Identifier can be:

  • Email address: john.doe@example.com
  • Phone number: (555) 123-4567 or 5551234567 or +1 555-123-4567

Step 3: Submit Login Request

Step 4: System Processing

  1. Auto-detects identifier type (EMAIL or PHONE)
  2. Normalizes identifier:
    • Email: Used as-is (case-sensitive)
    • Phone: Extracts last 10 digits → 5551234567
  3. Attempts JWT authentication
  4. Validates user status (ACTIVE required)
  5. Checks 2FA requirement (FALSE in this scenario)

Step 5: Response - Location Selection Required

Step 6: Select Location

Location Selection Dialog displays with available locations.

Step 7: System Validation

  1. Validates JWT token
  2. Checks user has access to location via user_locations pivot
  3. Validates location status (ACTIVE or STOP)
  4. Sets Spatie Permission context for location
  5. Creates AuthSession with refresh token
  6. Records LoginSession for audit

Step 8: Final Response - Authentication Complete

Step 9: Client Storage

  • Store access_token in memory or localStorage
  • Store refresh_token securely (HttpOnly cookie or secure storage)
  • Store user object
  • Redirect to dashboard

Scenario B: Employee Login with Two-Factor Authentication

Section titled “Scenario B: Employee Login with Two-Factor Authentication”

Steps 1-4: Same as Scenario A

Step 5: Response - 2FA Required

Step 6: Select Verification Method

2FA Method Selection Dialog displays:

  • Option 1: SMS to 55****67
  • Option 2: Email to u***@example.com

User selects: Email

Step 7: Request Verification Code

Step 8: System Processing

  1. Finds user by email
  2. Validates email format
  3. Resets verification attempts to 0
  4. Clears rate limit for fresh start
  5. Generates 6-digit code
  6. Hashes code with bcrypt
  7. Stores with 10-minute expiration (UTC)
  8. Sends code via email

Step 9: Code Sent Response

User receives email with subject: “Your PMC App Security Code”

Your verification code is: 123456
This code will expire in 10 minutes.
If you didn't request this code, please ignore this email.

Step 10: Enter Verification Code

2FA Verification Page displays:

  • 6-digit code input
  • Resend code button
  • Use backup code link
  • Time remaining indicator

Step 11: Code Verification

  1. Finds user by email
  2. Checks code expiration (auto-cleanup if expired)
  3. Verifies code using Hash::check() (constant-time)
  4. Increments attempts on failure
  5. Clears 2FA fields on success
  6. Generates JWT token
  7. Retrieves locations for selection
  8. Records login session

Step 12: Verification Success - Location Selection Required

Steps 13-15: Same as Scenario A Steps 6-9 (Location selection and final response)


Step 1: Navigate to Login Page

  • Opens application at /login
  • May have separate parent login form or unified form

Step 2: Enter Credentials

Identifier: parent@example.com
Password: ********

Step 3: Submit Login Request

Step 4: System Processing

  1. Uses apiparent guard
  2. Auto-detects and normalizes identifier
  3. Attempts JWT authentication
  4. Validates parent status (ACTIVE, not BLACK_LIST)
  5. Checks 2FA requirement (TRUE in this scenario)

Step 5: Response - 2FA Method Selection

Steps 6-9: Same as Employee 2FA (Method selection and code sending)

Step 10: Enter Verification Code

Step 11: Verification Success - Immediate Access

Key Difference: Parents receive tokens immediately without location selection.


Admin View: Special location providing cross-location visibility.

Steps 1-4: Standard Employee Login

Step 5: Location Selection Dialog

Available locations include:

  • Regular locations: Miami Clinic, Orlando Clinic
  • Admin View (if user has access_admin_view permission)

Step 6: Select Admin View

Step 7: Validation

  1. Checks user has access_admin_view global permission
  2. Sets admin view context
  3. Loads all-locations permissions

Step 8: Response


  • Q: What happens if I enter an invalid email format?

    • A: The system detects it as a PHONE identifier and tries phone-based lookup. If not found, returns “Invalid credentials.”
  • Q: Can I login with partial phone numbers?

    • A: The system normalizes all phone inputs to the last 10 digits. Formats like 555-1234, (555) 123-4567, or +1 555-123-4567 all become 5551234567.
  • Q: What happens if 2FA code expires while I’m on the verification page?

    • A: When you submit the expired code, the system auto-cleans it and returns: {"error": "Verification code has expired", "code_expired": true}. Click “Resend Code” to get a new one.
  • Q: What happens after 5 failed verification attempts?

    • A: The code is automatically cleared and you must request a new one. Returns: {"error": "Maximum attempts exceeded", "attempts_remaining": 0}.
  • Q: What if I don’t have access to any locations?

    • A: Authentication succeeds but location selection shows empty list. Contact your administrator to grant location access via user_locations table.
  • Q: Can SUPERADMIN bypass location selection?

    • A: No, ALL users must have explicit location access. SUPERADMIN must have user_locations entries just like any other user.
  • Q: What happens if I select an inactive location?

    • A: Location selection validates status. Only ACTIVE or STOP locations are allowed. Inactive locations are hidden from the list.
  • Q: Can I switch locations after logging in?

    • A: Yes, use the location switcher in the header or call POST /api/auth/change-location with a new location_id. This requires re-authentication with JWT.
  • Q: What happens if the location I’m using becomes inactive during my session?

    • A: Your current session continues until token expiration. However, you cannot refresh the token or switch back to that location.

2FA Bypass for Testing:

When it is not on AND TWO_FACTOR_ENABLED=true:

  • Any 6-digit code is accepted for LOGIN context
  • Real codes still required for PASSWORD_RESET context
  • Codes logged to Laravel log for debugging
  • SMS not sent (saves cost)

Example Log:

[2026-03-31 10:00:00] local.INFO: 2FA Development Mode: Generated code 123456 for user user@example.com

Identifier Normalization:

  • Phone: Last 10 digits only (US format)
  • Email: Case-sensitive, no transformation
  • Prevents timing attacks (same processing time)

Password Security:

  • Bcrypt hashing (cost factor from config)
  • Constant-time comparison via Hash::check()
  • No password in responses or logs

Session Tracking:

  • Every login recorded in login_sessions table
  • IP address, device, browser, OS captured
  • Audit trail for security monitoring

Error Messages:

  • Generic “Invalid credentials” for wrong email/password
  • No indication if email exists or not
  • Prevents user enumeration attacks

Rate Limiting:

  • Applied to 2FA endpoints
  • Prevents brute-force attacks
  • Configurable thresholds