Skip to content

Two-Factor Authentication (2FA)

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

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

Two-Factor Authentication (2FA) adds an extra layer of security by requiring users to verify their identity with a time-sensitive code delivered via SMS or Email. It supports backup codes for recovery, global policy enforcement, and flexible configuration for development and production environments.

  • All Users: Can enable/disable 2FA for their own account (subject to policy).
  • Superadmin: Can enforce 2FA globally for all users via configuration.
  • System Administrators: Can run policy enforcement commands to ensure compliance.
  • No special permissions required to use 2FA once enabled.
  • Rule 1: 2FA can be enforced globally in production (TWO_FACTOR_ENABLED=true + production environment).
  • Rule 2: Verification codes are 6 digits, expire after 10 minutes (UTC timezone).
  • Rule 3: Maximum 5 verification attempts per code.
  • Rule 4: Rate limit: 20 codes per hour per method (SMS/Email).
  • Rule 5: Backup codes are 8 codes of 10 characters each, one-time use only.
  • Rule 6: SMS requires valid phone number (10+ digits). Email requires valid email format.
  • Rule 7: Regenerating backup codes requires current password verification.
  • Rule 8: Password reset always requires 2FA verification regardless of enablement status.
  • Rule 9: In development mode (LOGIN context only), any 6-digit code is accepted.
  • Rule 10: Users cannot disable 2FA if globally enforced in production.
  • Location: User Settings > Security > Two-Factor Authentication
  • Features: Enable/disable toggle, view status, regenerate backup codes
  • Location: /two-factor-verification
  • Components: Code input, resend button, backup code link, method selection
  • Trigger: After enabling 2FA or regenerating codes
  • Warning: One-time display with download/copy options

Scenario A: Enabling Two-Factor Authentication

Section titled “Scenario A: Enabling Two-Factor Authentication”

Step 1: Navigate to Security Settings

  • Go to User Settings
  • Click on Security tab
  • Locate Two-Factor Authentication section

Step 2: View Current Status

Step 3: Click “Enable 2FA” Button

Prerequisites Check:

  • Must have valid phone number (10+ digits)
  • Not already enabled

Step 4: System Processing

  1. Validates user has valid phone
  2. Skips phone verification in development
  3. Calls user->enableTwoFactor()
  4. Generates 8 backup codes (10 characters each)
  5. Sends backup codes via SMS (production only)

Step 5: Response with Backup Codes

Step 6: Save Backup Codes

IMPORTANT: These codes are shown only once!

Save options:

  • Download as text file
  • Copy to password manager
  • Print and store securely

Warning displayed:

⚠️ IMPORTANT: Save These Codes Now!
These backup codes are your only way to access your account if you lose
your phone or email access. Each code can only be used once.
Store them in a safe place:
✓ Password manager
✓ Encrypted file
✓ Secure physical location
❌ DO NOT:
- Share with anyone
- Store in plain text
- Take screenshots
- Email to yourself

Step 7: Confirmation

2FA is now enabled. Next login will require verification code.


Scenario B: Disabling Two-Factor Authentication

Section titled “Scenario B: Disabling Two-Factor Authentication”

Prerequisites:

  • 2FA currently enabled
  • Policy allows disabling (not enforced globally)
  • Current password required

Step 1: Navigate to Security Settings

Step 2: Click “Disable 2FA” Button

Step 3: Enter Current Password

Dialog prompts for password confirmation:

Disable Two-Factor Authentication
This will remove the extra security layer from your account.
You will no longer need verification codes to log in.
Current Password: ********
[Cancel] [Disable 2FA]

Step 4: Submit Disable Request

Step 5: System Validation

  1. Checks if policy allows disabling
  2. Verifies current password
  3. Confirms 2FA is currently enabled
  4. Calls TwoFactorService::disable()

Step 6: Success Response

Step 7: Database Update

All 2FA fields cleared:


Scenario C: Regenerating Backup Codes (Not Ready yet)

Section titled “Scenario C: Regenerating Backup Codes (Not Ready yet)”

When to use:

  • Used several backup codes and want fresh set
  • Suspect codes may be compromised
  • Lost original codes (if still have phone/email access)

Step 1: Navigate to Security Settings

Step 2: Click “Generate New Backup Codes”

Step 3: Enter Current Password

Security confirmation dialog:

Step 4: Submit Request

Step 5: System Validation

  1. Requires current password verification
  2. Requires 2FA already enabled
  3. Generates 8 new codes
  4. Invalidates all previous codes

Step 6: Response with New Codes

Step 7: Save New Codes

Same saving procedure as initial enablement.


Scenario D: Sending Verification Code (Method Selection)

Section titled “Scenario D: Sending Verification Code (Method Selection)”

Context: During login after credentials verified.

Step 1: Login Successful - 2FA Required

Response includes available methods:

Step 2: Method Selection Dialog

Verify Your Identity
To keep your account secure, please verify your identity.
Choose how you want to receive your verification code:
○ Text Message (SMS)
Send code to 55****67
○ Email
Send code to u***@example.com
[Cancel] [Send Code]

Step 3: Send Code Request

Step 4: System Processing

  1. Validates request (email, method, context)
  2. Finds user in Users or Parents table
  3. Validates method requirements:
    • SMS: Checks hasValidPhoneForTwoFactor()
    • Email: Validates email format
  4. Resets verification attempts to 0
  5. Clears rate limit for fresh start
  6. Generates 6-digit code
  7. Hashes code with bcrypt
  8. Stores with metadata
  9. Dispatches code via selected method

SMS Dispatch (Production):

Email Dispatch:

Step 5: Success Response

Step 6: User Receives Code

Via SMS:

Your PMC App verification code is: 123456
This code expires in 10 minutes.

Via Email:

Subject: Your PMC App Security Code
Hello John Doe,
Your verification code is: 123456
This code will expire in 10 minutes.
If you didn't request this code, please ignore this email.
Best regards,
PMC App Team

When to use:

  • Code not received
  • Code expired
  • Want to try different method

Step 1: Click “Resend Code” Button

Resend dialog:

Didn't Receive Code?
Choose a delivery method:
○ Text Message (SMS) - 55****67
○ Email - u***@example.com
[Cancel] [Resend Code]

Step 2: Submit Resend Request

Key Difference from send-code:

  • Resets attempts to 0 (fresh start)
  • Clears rate limit
  • Used during active verification flow

Step 3: Success Response


Trigger: Sending more than 20 codes per hour per method.

User sees:

Too Many Requests
You've requested too many SMS verification codes.
Please try again in 1 hour, or use Email verification instead.
[Try Email Instead]

  • Q: What happens if I lose all my backup codes?

    • A: If you still have access to your phone or email, you can log in normally with 2FA codes. Once logged in, regenerate new backup codes in Security Settings. If you’ve lost both (phone/email AND backup codes), contact your system administrator to reset your 2FA.
  • Q: Can I use the same backup code twice?

    • A: No, backup codes are single-use only. After using a code, it’s permanently removed from your account. This is a security feature to prevent code reuse attacks.
  • Q: What if my verification code expires while I’m entering it?

    • A: The system auto-detects expired codes on submission. You’ll see: “Verification code has expired.” Click “Resend Code” to receive a fresh one.
  • Q: What happens after I fail 5 verification attempts?

    • A: The code is automatically cleared and you must request a new one. This prevents brute-force attacks. Your account is not locked - just request a new code.
  • Q: Can I have 2FA on email only (no phone)?

    • A: Yes, if you have a valid email but no phone, only email method will be available. However, some organizations may require phone numbers for SMS verification.
  • Q: What happens in development mode?

    • A: For LOGIN context, any 6-digit code (e.g., 111111, 123456, 999999) is accepted. This is for testing convenience. For PASSWORD_RESET context, real codes are always required. In production, this bypass is disabled.
  • Q: How long are backup codes valid?

    • A: Backup codes never expire unless you regenerate them or disable 2FA. Store them permanently in a secure location.
  • Q: Can administrators see my 2FA codes?

    • A: No, codes are hashed with bcrypt before storage. Nobody can retrieve your plain text codes, not even administrators. However, administrators can reset your 2FA settings if needed.
  • Q: What happens if I enable 2FA but don’t save backup codes?

    • A: You can still use SMS/Email verification. However, if you lose phone and email access, you’ll need administrator assistance to regain access. Always save backup codes!
  • Q: Can I disable 2FA in production?

    • A: This depends on your organization’s policy. If 2FA is globally enforced in production, the disable option will be grayed out with a message: “Two-factor authentication is required by your organization and cannot be disabled.”

Terminal window
php artisan two-factor:enforce-policies [--dry-run]

Auto-enables 2FA for users without it (if globally required):


Code Storage:

  • Never stored in plain text
  • Bcrypt hashing (one-way)

Expiration:

  • 10 minutes (configurable)
  • UTC timezone for consistency
  • Automatic cleanup on verification attempt

Attempt Limiting:

  • Maximum 5 attempts per code
  • Auto-clears code after max attempts
  • Forces new code request

Rate Limiting:

  • Per user, per method
  • 20 codes per hour default
  • Prevents abuse and cost

Backup Codes:

  • 8 codes for redundancy
  • Single-use prevents reuse
  • Regeneration requires password
  • Stored hashed like regular codes

Development Mode:

  • Only affects LOGIN context
  • PASSWORD_RESET always requires real codes
  • Disabled in production automatically
  • Logs codes for debugging