ADR-006: Two-Factor Authentication Implementation
Status
Section titled “Status”Proposed
Context
Section titled “Context”XOOPS needs enhanced security for user authentication. Two-factor authentication (2FA) provides an additional layer of security beyond passwords, protecting accounts even if passwords are compromised.
Key considerations:
- Backward compatibility with existing authentication
- Support for multiple 2FA methods
- User experience during setup and login
- Recovery mechanisms for lost devices
- Integration with existing permission system
Decision
Section titled “Decision”We will implement TOTP (Time-based One-Time Password) as the primary 2FA method with support for backup codes.
Implementation Approach
Section titled “Implementation Approach”sequenceDiagram participant U as User participant X as XOOPS participant T as TOTP Library participant D as Database
U->>X: Login with password X->>D: Validate password D-->>X: Password valid X->>D: Check 2FA enabled D-->>X: 2FA required X->>U: Request 2FA code U->>X: Submit TOTP code X->>T: Validate code T-->>X: Code valid X->>U: Login successfulDatabase Schema
Section titled “Database Schema”CREATE TABLE `{PREFIX}_users_2fa` ( `user_id` INT(11) NOT NULL, `secret` VARCHAR(32) NOT NULL, `enabled` TINYINT(1) DEFAULT 0, `backup_codes` TEXT, `last_used` INT(11), `created` INT(11) NOT NULL, PRIMARY KEY (`user_id`), FOREIGN KEY (`user_id`) REFERENCES `{PREFIX}_users`(`uid`));Service Interface
Section titled “Service Interface”interface TwoFactorAuthInterface{ public function enable(int $userId): TwoFactorSetup; public function disable(int $userId): void; public function verify(int $userId, string $code): bool; public function generateBackupCodes(int $userId): array; public function isEnabled(int $userId): bool;}Middleware Integration
Section titled “Middleware Integration”class TwoFactorMiddleware implements MiddlewareInterface{ public function process( ServerRequestInterface $request, RequestHandlerInterface $handler ): ResponseInterface { $session = $request->getAttribute('session');
if ($session->has('pending_2fa_user_id')) { // User needs to complete 2FA if ($this->isVerificationRequest($request)) { return $handler->handle($request); } return new RedirectResponse('/2fa/verify'); }
return $handler->handle($request); }}Consequences
Section titled “Consequences”Positive
Section titled “Positive”- Significantly improved account security
- Industry-standard TOTP compatibility (Google Authenticator, Authy, etc.)
- Backup codes prevent account lockout
- Optional per-user - doesn’t force adoption
- PSR-15 middleware allows clean integration
Negative
Section titled “Negative”- Additional login step impacts user experience
- Users must manage authenticator apps
- Lost devices require recovery process
- Additional database storage and queries
- Requires cryptographic library dependency
Migration Path
Section titled “Migration Path”- Add database table for 2FA data
- Implement TOTP service with library dependency
- Add middleware to authentication chain
- Create setup and verification UI
- Admin option to require 2FA for specific groups
Alternatives Considered
Section titled “Alternatives Considered”SMS-based OTP
Section titled “SMS-based OTP”Rejected due to:
- SIM swapping vulnerabilities
- Cost of SMS gateway
- Phone number verification complexity
- Privacy concerns
Hardware Security Keys (WebAuthn)
Section titled “Hardware Security Keys (WebAuthn)”Deferred for future ADR:
- More complex implementation
- Limited browser support historically
- Higher user cost
- Could be added alongside TOTP later
Email-based OTP
Section titled “Email-based OTP”Rejected due to:
- Email account compromise defeats purpose
- Delivery delays impact UX
- Spam filter issues
References
Section titled “References”- RFC 6238 - TOTP
- Google Authenticator Key Format
- ../../02-Core-Concepts/Security/Security-Best-Practices - Security guidelines
- ../../02-Core-Concepts/Users-Permissions/Authentication - Auth system documentation