Skip to content

Engine: Auth - 2FA #13

@ollieread

Description

@ollieread

Two-factor authentication adds a second verification step after credentials are validated. The system is built around a TwoFactorProvider contract so that multiple methods can be supported. For launch, TOTP and recovery codes are in scope. Email OTP and SMS OTP are planned post-launch extensions.

TwoFactorProvider

TwoFactorProvider is a contract that all 2FA method implementations satisfy. It exposes:

  • verify(User $user, string $code): bool — verifies a submitted code against the user's configured state for this provider
  • isEnabled(User $user): bool — checks whether this provider is enabled for the given user

Challenge Flow

When Authenticator::fromCredentials() detects that the user has 2FA enabled, it does not issue a token. Instead it generates a TwoFactorChallenge and returns it to the caller. The challenge contains:

  • A short-lived signed challenge token — single-use, tied to the user, IP address, and user agent, expires after a few minutes
  • The URL of the 2FA validation endpoint

The client submits the challenge token alongside the 2FA code to the validation endpoint. The endpoint verifies the challenge token is valid, unexpired, and unused, then delegates code verification to the appropriate TwoFactorProvider. On success, the challenge token is consumed and a RawToken is issued.

Subissues

  • Engine: Auth — 2FA TOTP
  • Engine: Auth — 2FA recovery codes
  • Engine: Auth — 2FA email OTP (post-launch)
  • Engine: Auth — 2FA SMS OTP (post-launch)

Tasks

  • Define TwoFactorProvider contract
  • Implement TwoFactorChallenge value object
  • Implement challenge token generation — signed, single-use, tied to user, IP, and user agent
  • Implement challenge token validation — signature check, expiry check, consumed check
  • Implement 2FA validation endpoint flow — validate challenge token, delegate to provider, issue RawToken
  • Write tests for challenge token generation and validation
  • Write tests for expired challenge token rejection
  • Write tests for consumed challenge token rejection
  • Write tests for IP and user agent mismatch rejection

Metadata

Metadata

Assignees

Labels

area: authAuthentication and authorisationlayer: engineBase framework and engine work

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions