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.
2. Who is this for? (Roles & Permissions)
Section titled “2. Who is this for? (Roles & Permissions)”- 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.
3. Business Rules & Enforcements
Section titled “3. Business Rules & Enforcements”- Rule 1: 2FA can be enforced globally in production (
TWO_FACTOR_ENABLED=true+productionenvironment). - 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.
4. UI Placement
Section titled “4. UI Placement”2FA Management
Section titled “2FA Management”- Location: User Settings > Security > Two-Factor Authentication
- Features: Enable/disable toggle, view status, regenerate backup codes
2FA Verification (Login Flow)
Section titled “2FA Verification (Login Flow)”- Location:
/two-factor-verification - Components: Code input, resend button, backup code link, method selection
Backup Codes Display
Section titled “Backup Codes Display”- Trigger: After enabling 2FA or regenerating codes
- Warning: One-time display with download/copy options
5. How-To Guide (Step-by-Step)
Section titled “5. How-To Guide (Step-by-Step)”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
- Validates user has valid phone
- Skips phone verification in development
- Calls
user->enableTwoFactor() - Generates 8 backup codes (10 characters each)
- 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 loseyour 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 yourselfStep 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
- Checks if policy allows disabling
- Verifies current password
- Confirms 2FA is currently enabled
- 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
- Requires current password verification
- Requires 2FA already enabled
- Generates 8 new codes
- 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
- Validates request (email, method, context)
- Finds user in Users or Parents table
- Validates method requirements:
- SMS: Checks
hasValidPhoneForTwoFactor() - Email: Validates email format
- SMS: Checks
- Resets verification attempts to 0
- Clears rate limit for fresh start
- Generates 6-digit code
- Hashes code with bcrypt
- Stores with metadata
- 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 TeamScenario E: Resending Verification Code
Section titled “Scenario E: Resending Verification Code”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
Scenario F: Rate Limit Exceeded
Section titled “Scenario F: Rate Limit Exceeded”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]6. What happens if…? (Edge Cases / FAQ)
Section titled “6. What happens if…? (Edge Cases / FAQ)”-
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.”
Technical Details
Section titled “Technical Details”Console Commands
Section titled “Console Commands”Enforce Policies
Section titled “Enforce Policies”php artisan two-factor:enforce-policies [--dry-run]Auto-enables 2FA for users without it (if globally required):
Security Considerations
Section titled “Security Considerations”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