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:
- Open the Firebase Console and navigate to your project
- Go to Authentication › Sign-in method
- 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.IsEMailVerifiedbefore 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)
- User signs in with email/password (standard sign-in)
- After successful sign-in, call
StartMfaTotpEnrollmentto request enrollment info from Firebase - Display the QR code (generated from the enrollment info) to the user
- User scans the QR code with their authenticator app
- User enters the 6-digit verification code from the app
- Call
FinalizeMfaTotpEnrollmentto complete the enrollment
Phase 2: MFA-aware Sign-In (every subsequent login)
- Call
SignInWithEmailAndPasswordWithMFAinstead ofSignInWithEmailAndPassword - If the user has MFA enrolled, Firebase returns a pending credential and the
OnMfaRequiredcallback fires - Display a TOTP code entry screen to the user
- User enters the 6-digit code from their authenticator app
- Call
MfaSignInwith 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:
- Config Tab: Enter your Firebase API Key and Project ID
- Login Tab: Sign in with email/password, or sign up a new user
- MFA Enrollment Tab: Start TOTP enrollment, scan QR code, enter verification code
- Enter MFA Code Tab: Enter the OTP during MFA-required sign-in
- 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 |