Two-Factor Authentication (2FA) with Device Management Flow
Overview
This document describes the complete implementation of Two-Factor Authentication (2FA) with device trust management in the Kulcare platform. The system supports three 2FA methods (TOTP, SMS, EMAIL) and allows users to trust devices to bypass 2FA on subsequent logins.
Table of Contents
- Key Features
- Architecture Components
- 2FA Setup Flow
- Login Flow with 2FA
- Device Trust Management
- Technical Implementation Details
- User Experience Enhancements
- Security Considerations
- Visual Flow Diagram
Key Features
Supported 2FA Methods
- TOTP (Time-based One-Time Password): Using authenticator apps like Google Authenticator
- SMS: Verification codes sent via text message
- EMAIL: Verification codes sent via email
Device Trust Features
- Persistent device identification using UUID
- "Remember this device" option during login
- Device trust survives logout (UUID preserved)
- Centralized device management interface
- Trust/untrust devices from settings
Architecture Components
Frontend Components
-
TwoFactorSetup (
/components/settings/TwoFactorSetup.tsx)- Handles 2FA method selection
- Manages setup flow for each method
- Shows device trust consent modal for SMS/EMAIL
-
TwoFactorVerification (
/components/auth/TwoFactorVerification.tsx)- OTP input interface during login
- "Remember this device" checkbox for SMS/EMAIL
- Recovery code support
-
DeviceManagement (
/components/settings/DeviceManagement.tsx)- Lists all devices (trusted and untrusted)
- Shows device details (name, browser, last IP)
- Trust/revoke trust controls
-
DeviceTrustConsentModal (
/components/settings/DeviceTrustConsentModal.tsx)- Explains device trust feature during setup
- Warns about potential re-login requirement
Services and APIs
-
deviceApi.ts
getDevices(): List all user devicestrustDevice(): Mark device as trustedrevokeTrust(): Remove device trust
-
twoFactorApi.ts
enable(): Enable 2FA methodconfirm(): Confirm setup with codeverify(): Verify 2FA during login with device trust option
-
deviceInfo.ts (api-client package)
- Generates and persists device UUID
- Collects device information (browser, OS, version)
- Creates browser fingerprint for web devices
2FA Setup Flow
Step 1: Method Selection
User navigates to Settings > Security > Two-Factor Authentication
↓
Selects method: TOTP, SMS, or EMAIL
↓
For SMS/EMAIL: Device Trust Consent Modal appears
- Explains device trust feature
- Notes possible re-login requirement
↓
User proceeds with setupStep 2: Method-Specific Setup
TOTP Setup:
- Backend generates QR code and secret
- User scans QR with authenticator app
- User enters 6-digit code to confirm
- Recovery codes displayed
SMS Setup:
- Shows masked phone number
- SMS automatically sent
- User enters verification code
- Recovery codes displayed
EMAIL Setup:
- Shows masked email address
- Email automatically sent
- User enters verification code
- Recovery codes displayed
Step 3: Recovery Codes
- 5 recovery codes generated
- User must save/download codes
- Confirmation required before proceeding
Login Flow with 2FA
First Login (No Device Trust)
1. User enters phone + password
↓
2. Backend checks if 2FA enabled
↓
3. If enabled: Returns temp_auth_token + 2FA method
↓
4. Frontend shows 2FA verification screen
↓
5. For SMS/EMAIL: "Remember this device" checkbox shown
↓
6. User enters code + optionally checks "Remember"
↓
7. Frontend sends:
- code
- method
- trust_device: true/false
- device_uuid
- device_details
↓
8. Backend verifies code
↓
9. If trust_device=true: Device registered as trusted
↓
10. Auth tokens returned
↓
11. User may need to re-login once (expected behavior)Subsequent Login (Device Trusted)
1. User enters phone + password
↓
2. Frontend sends login with device_details
↓
3. Backend recognizes trusted device UUID
↓
4. 2FA skipped automatically
↓
5. Direct login to dashboardDevice Trust Management
Device Identification
Each device is identified by:
- device_uuid: Persistent UUID stored in localStorage
- device_type: Always "web" for browser apps
- device_name: Browser name + OS (e.g., "Chrome on Linux")
- app_type: "cms" for the CMS application
- browser_fingerprint: JSON with user agent, screen size, timezone
Device UUID Persistence
// UUID Generation (deviceInfo.ts)
function getDeviceUUID(): string {
const STORAGE_KEY = 'kulcare-device-uuid'
let uuid = localStorage.getItem(STORAGE_KEY)
if (!uuid) {
uuid = generateUUID()
localStorage.setItem(STORAGE_KEY, uuid)
}
return uuid
}Logout Behavior
The device UUID is specifically preserved during logout:
// Auth store logout
keys.forEach(key => {
if (key === "kulcare-device-uuid") {
// Preserve device UUID for trusted device functionality
return
}
// Remove other localStorage items
})Device Management UI
The DeviceManagement component shows:
- All devices with trust status
- Trust indicators (green for trusted, gray for untrusted)
- Device details (browser, version, last IP)
- Trust/Revoke buttons
- Summary cards (total trusted/untrusted)
Technical Implementation Details
API Request Structure
Login with Device Details:
{
"user_signin_form": {
"country_code": "+1",
"phone_number": "1234567890",
"password": "password",
"platform": "web"
},
"device_details": {
"device_uuid": "uuid-here",
"device_type": "web",
"device_token": "uuid-here",
"device_name": "Chrome on macOS",
"device_version": "Chrome 120.0",
"app_version": "1.0.0",
"app_type": "cms",
"browser_fingerprint": "{...}"
}
}2FA Verification with Trust:
{
"code": "123456",
"method": "SMS",
"trust_device": true,
"device_uuid": "uuid-here",
"device_details": { /* same as above */ }
}State Management
- Device UUID: Stored in localStorage
- Auth tokens: Managed by Zustand auth store
- Device list: Fetched on demand, not cached
User Experience Enhancements
Warning Messages
-
During 2FA Setup (SMS/EMAIL):
- "Note: You may need to sign in again after OTP verification when first enabling this feature."
-
During Login (when checkbox checked):
- "Note: You may need to sign in once more after verification"
Visual Indicators
- Trusted devices: Green background with shield check icon
- Untrusted devices: Gray background with shield off icon
- Current device: "(This device)" label
- Trust status badges
Error Handling
- "Devices do not exist" API error handled gracefully
- Empty device list shows helpful message
- Network errors show toast notifications
Security Considerations
- Device UUID Persistence: Survives logout but not browser data clearing
- Trust Revocation: Invalidates all sessions on that device
- IP Tracking: Last trusted IP stored for security monitoring
- No Silent Trust: User must explicitly check "Remember this device"
- Recovery Codes: One-time use, securely generated
Visual Flow Diagram
Device Management Flow
Summary
The 2FA with device management system provides a secure yet user-friendly authentication experience. Key achievements:
- Persistent Device Identity: Device UUID survives logout
- User Control: Explicit consent for device trust
- Transparent UX: Clear warnings about re-login requirement
- Comprehensive Management: Full device visibility and control
- Secure Implementation: Follows security best practices
The implementation balances security requirements with user convenience, allowing trusted devices to bypass 2FA while maintaining full user control over device trust status.