Multi Factor Authentication TOTP - SchneiderInfosystems/FB4D GitHub Wiki

Multi-Factor Authentication (MFA) with TOTP

Firebase Authentication supports Multi-Factor Authentication (MFA) as an additional security layer. FB4D implements the TOTP (Time-based One-Time Password) variant that works with standard authenticator apps such as Google Authenticator, Microsoft Authenticator, or Authy.

Prerequisites

Before using MFA in your application, you must enable Multi-Factor Authentication in the Firebase Console:

  1. Open the Firebase Console and navigate to your project
  2. Go to AuthenticationSign-in method
  3. In the Multi-factor authentication section, enable TOTP as a second factor

Important: MFA requires that the user's email address is verified. The FB4D library enforces this by checking IFirebaseUser.IsEMailVerified before allowing enrollment. Make sure to implement email verification in your sign-up workflow.

MFA Workflow Overview

The MFA integration consists of two main phases:

Phase 1: TOTP Enrollment (one-time setup)

  1. User signs in with email/password (standard sign-in)
  2. After successful sign-in, call StartMfaTotpEnrollment to request enrollment info from Firebase
  3. Display the QR code (generated from the enrollment info) to the user
  4. User scans the QR code with their authenticator app
  5. User enters the 6-digit verification code from the app
  6. Call FinalizeMfaTotpEnrollment to complete the enrollment

Phase 2: MFA-aware Sign-In (every subsequent login)

  1. Call SignInWithEmailAndPasswordWithMFA instead of SignInWithEmailAndPassword
  2. If the user has MFA enrolled, Firebase returns a pending credential and the OnMfaRequired callback fires
  3. Display a TOTP code entry screen to the user
  4. User enters the 6-digit code from their authenticator app
  5. Call MfaSignIn with the pending credential and verification code to complete authentication

Interface Methods

The following methods are available on IFirebaseAuthentication:

SignInWithEmailAndPasswordWithMFA

MFA-aware sign-in that automatically detects whether a user has MFA enrolled. If no MFA is required, it behaves like a normal SignInWithEmailAndPassword.

procedure SignInWithEmailAndPasswordWithMFA(const Email, Password: string;
  OnUserResponse: TOnUserResponse; OnMfaRequired: TOnMfaRequired;
  OnError: TOnRequestError);
Parameter Description
Email The user's email address
Password The user's password
OnUserResponse Called on successful sign-in (no MFA required, or MFA already completed)
OnMfaRequired Called when the user has MFA enrolled and needs to provide a TOTP code
OnError Called if the sign-in fails (wrong credentials, network error, etc.)

StartMfaTotpEnrollment

Initiates the TOTP enrollment process. The user must already be signed in. On success, the callback provides a TMfaTotpEnrollmentInfo record containing the shared secret and session info needed to generate the QR code.

procedure StartMfaTotpEnrollment(OnMfaTotpEnrollment: TOnMfaEnrollment;
  OnError: TOnRequestError);

FinalizeMfaTotpEnrollment

Completes the TOTP enrollment by verifying the code entered by the user. Returns false if StartMfaTotpEnrollment was not called before. On success, the OnUserResponse callback is fired with the updated user info.

function FinalizeMfaTotpEnrollment(const VerificationCode, DisplayName: string;
  OnUserResponse: TOnUserResponse; OnError: TOnRequestError): boolean;
Parameter Description
VerificationCode The 6-digit TOTP code from the authenticator app
DisplayName A display name for this MFA factor (e.g. the issuer name)

MfaSignIn

Finishes the MFA sign-in process by verifying the TOTP code against the pending credential received in the OnMfaRequired callback.

procedure MfaSignIn(const PendingCredential: TMfaPendingCredential;
  const VerificationCode: string;
  OnUserResponse: TOnUserResponse; OnError: TOnRequestError);
Parameter Description
PendingCredential The TMfaPendingCredential record from the OnMfaRequired callback
VerificationCode The 6-digit TOTP code from the authenticator app

Data Types

TMfaPendingCredential

This record is populated from the sign-in response when a user has MFA enrolled. It must be passed to MfaSignIn to complete authentication.

TMfaPendingCredential = record
  MfaPendingCredential: string; // Temporary credential from the first sign-in step
  MfaEnrollmentId: string;      // Enrollment ID of the MFA factor to verify
  MfaDisplayName: string;       // Display name of the enrolled factor (informational)
  PhoneResolver: string;        // Phone number for SMS-based MFA (empty for TOTP)
end;

TMfaTotpEnrollmentInfo

This record contains all information returned by StartMfaTotpEnrollment that is needed to generate a QR code and complete the enrollment.

TMfaTotpEnrollmentInfo = record
  Created: TDateTime;
  SharedSecretKey: string;
  VerificationCodeLength: integer;
  HashingAlgorithm: string;
  PeriodSec: integer;
  SessionInfo: string;
  procedure Init(ServerLocalTime: TDateTime = 0);
  function IsValid: boolean;
  function CalcQrCodeURL(const EMail, IssuerName: string): string;
end;

The CalcQrCodeURL method generates a standard otpauth:// URI that can be encoded as a QR code and scanned by any TOTP authenticator app.

Callback Types

TOnMfaRequired = procedure(PendingCredential: TMfaPendingCredential) of object;
TOnMfaEnrollment = procedure(const EnrollmentInfo: TMfaTotpEnrollmentInfo) of object;

Sample Application: MultiFactorAuthentication

The sample application Samples\MultiFactorAuthentication demonstrates the complete MFA workflow as a Firemonkey cross-platform application. It is organized in a step-by-step wizard with 5 tabs:

  1. Config Tab: Enter your Firebase API Key and Project ID
  2. Login Tab: Sign in with email/password, or sign up a new user
  3. MFA Enrollment Tab: Start TOTP enrollment, scan QR code, enter verification code
  4. Enter MFA Code Tab: Enter the OTP during MFA-required sign-in
  5. Test Tab: Test the complete MFA sign-in flow

QR Code Rendering

The sample uses the DelphiZXingQRCode library to render the TOTP enrollment URI as a QR code that can be scanned with any authenticator app.

Usage Flow

┌─────────────────────────────────────────────────────────────┐
│  1. Enter API Key & Project ID → Initialize                 │
│  2. Enter email & password → Sign In or Sign Up             │
│  3. If new user: email verification is sent automatically   │
│  4. Start MFA Enrollment → Scan QR Code → Enter OTP         │
│  5. Sign Out → Sign In again → Enter OTP → Authenticated!   │
└─────────────────────────────────────────────────────────────┘

Key Code Excerpts

MFA-aware sign-in:

fConfig.Auth.SignInWithEmailAndPasswordWithMFA(
  edtEmail.Text, edtPassword.Text,
  OnUserResponse,   // called when no MFA or after MfaSignIn
  OnMfaRequired,    // called when OTP is needed
  OnError);

Handle MFA requirement:

procedure TfmxMainMFA.OnMfaRequired(PendingCredential: TMfaPendingCredential);
begin
  fMfaPending := PendingCredential;
  TabControl.ActiveTab := tabEnterMFACode;
  edtTestMfaCode.SetFocus;
end;

Complete MFA sign-in:

fConfig.Auth.MfaSignIn(fMfaPending, edtTestMfaCode.Text,
  OnUserResponse, OnError);

Firebase REST API Endpoints

FB4D uses the Identity Toolkit v2 API for MFA operations:

Operation Endpoint
Start Enrollment POST /v2/accounts/mfaEnrollment:start
Finalize Enrollment POST /v2/accounts/mfaEnrollment:finalize
Sign-In with MFA POST /v2/accounts/mfaSignIn:finalize
Standard Sign-In (MFA detection) POST /v1/accounts:signInWithPassword