KAHIBARO
Discord Login Register

13.16. Multi-Factor Authentication

Why Multi-Factor Authentication Matters

Multi Factor Authentication, often shortened to MFA, adds extra protection on top of a username and password. Instead of trusting only "something you know" like a password, MFA requires at least one more factor before the user is allowed in.

Common factors are:

Factor typeDescriptionExamples
Something you knowA secret in your headPassword, PIN, answer to a security question
Something you haveA physical object or devicePhone with authenticator app, hardware token
Something you areA physical or behavioral traitFingerprint, face, voice, retina
Somewhere you areLocation basedLogging in only from a specific country
Something you doBehavioral patternTyping rhythm, way you move the mouse

With MFA, an attacker who steals a password still cannot log in, because they do not have the second factor.

Core idea: MFA requires at least two independent factors from different categories, for example password + time based one time code.

As a backend developer, you do not implement fingerprint scanners yourself, but you integrate MFA flows into your authentication system and make sure they are secure, reliable, and user friendly.

Typical MFA Flows

From a backend point of view, MFA is mostly about flows and state. Here are the most common flows you will implement.

Login with MFA

  1. User enters username and password.
  2. Backend verifies the password.
  3. If the account has MFA enabled, backend marks the user as "partially authenticated".
  4. Backend triggers the second factor, for example:
    • Shows a page asking for a 6 digit code.
    • Sends an email or SMS with a one time code.
    • Sends a push notification to a mobile app.
  5. User provides or approves the second factor.
  6. Backend completes authentication, creates final session or access token.

In code, you usually represent this as two steps:

This keeps logic clear and prevents partial logins from becoming full sessions by mistake.

Enabling MFA

When a user turns MFA on, you need a safe setup flow:

  1. User is already logged in with password.
  2. User chooses MFA method, for example "Authenticator app".
  3. Backend generates a shared secret and returns it as:
    • a QR code image (or URL for QR), or
    • a base32 encoded string.
  4. User scans the QR code into their authentication app (Google Authenticator, Authy, etc).
  5. App starts generating 6 digit codes.
  6. Backend asks user to enter one code to confirm they set it up correctly.
  7. Backend validates the code once.
  8. Backend stores the secret for that user in the database, and marks MFA as enabled.

Never enable MFA for a user without first verifying at least one valid code from their authenticator app.

Disabling MFA

Disabling MFA is sensitive, because an attacker with only a password should not be able to easily remove the extra protection.

Typical rules:

  1. Require the user to re enter their password.
  2. Optionally ask for a current MFA code as well.
  3. Only then mark MFA disabled and delete or archive MFA secrets.

You will later use some of the same ideas for password reset, email verification, and other security sensitive flows.

Common MFA Methods

You will meet several MFA methods as a backend developer. Each method has a different security level and integration style.

Time-Based One-Time Passwords (TOTP)

This is the most common strong MFA method. It uses a shared secret between the server and the user’s device.

How TOTP Works in Simple Terms

  1. Server generates a random secret key (for example 160 bits).
  2. Server shows the secret to the user as a base32 string or QR code.
  3. User stores this secret in an authenticator app.
  4. Every 30 seconds, both server and app compute a new 6 digit code from:
    • the shared secret
    • the current time window

The code is one time and short lived. Even if someone sees the code, they can only use it for a few seconds.

You do not need to implement the math yourself, most languages have libraries. Still, it helps to know the formula:

TOTP rule: Valid codes are only accepted for a small time window, usually the current 30 second step, and sometimes 1 step before and after to allow for small clock differences.

Example: Generating a TOTP Secret and QR URI

A common format for providing TOTP data to authenticator apps is the otpauth URI:

text
otpauth://totp/{ISSUER}:{ACCOUNT_NAME}?secret={BASE32_SECRET}&issuer={ISSUER}&digits=6&period=30

Example values:

As backend you return this URI to the frontend, which then renders it as a QR code.

Verifying a TOTP Code

When a user sends a 6 digit code, the backend:

  1. Looks up the stored secret for this user.
  2. Computes codes for:
    • current time step
    • maybe 1 step before and after
  3. Checks if any of those codes match the user input.

If yes, MFA step is passed. If not, reject and maybe increment a counter for failed attempts.

SMS and Email Codes

Some systems send one time codes over SMS or email. The flow is similar to TOTP but with important differences.

Typical flow:

  1. User starts login.
  2. Backend generates a random numeric code, for example 6 digits.
  3. Backend stores a hashed version of the code, together with:
    • the user id
    • expiration time, for example 5 minutes
    • number of remaining attempts
  4. Backend sends the plain code over SMS or email.
  5. User enters the code.
  6. Backend compares the hashed code and checks expiration and attempts.

You can represent stored codes in a table like:

FieldExample value
id123
user_id42
code_hashhash("483920")
created_at2026-08-27 12:30:00 UTC
expires_at2026-08-27 12:35:00 UTC
attempts_left3
usedfalse

Never store the code in plain text in the database. Store a hash of the code and compare hashes.

SMS and email codes are easier to integrate but less secure than TOTP. Attackers can sometimes intercept SMS or compromise email accounts.

Push Notification Approvals

Some apps use push notifications for MFA:

  1. User enters username and password.
  2. Backend sends a "login request" to a mobile app via push.
  3. Mobile app shows "Approve login?" prompt to the user.
  4. User taps "Approve".
  5. Mobile app calls a backend endpoint, for example /mfa/approve, with:
    • the login request id
    • a signed token or device secret
  6. Backend verifies the approval and completes login.

This requires:

The concept is similar to TOTP, but the "code" is replaced with "user physically approved this on a trusted device".

Hardware Security Keys (U2F / WebAuthn)

Hardware keys like YubiKey plug into USB or stay near the phone. Modern browsers support them through WebAuthn.

As a backend developer, you typically:

  1. Support "register security key" endpoint.
  2. Support "login with security key" endpoint.
  3. Use a WebAuthn library that handles:
    • challenges
    • cryptographic signatures
    • public key storage and verification.

The high level idea is:

Hardware security keys are one of the strongest MFA methods, but they are more advanced to integrate.

Designing MFA in Your Backend

Data Model for MFA

You need to store MFA configuration per user. A simple starting point:

ColumnTypeMeaning
idintegeruser id
mfa_enabledbooleanwhether MFA is required for login
mfa_typestringfor example totp, sms, email, webauthn
mfa_secretstring / blobTOTP secret or encrypted data
phone_numberstringfor SMS MFA
backup_codes_hashesjsonlist of hashed backup codes
last_mfa_verified_attimestamplast time MFA was successfully passed

For TOTP you usually store mfa_secret. For SMS or email, you may not need a long term secret, but you need fields to store temporary codes.

You might also use a separate table for MFA methods if you want multiple methods per user.

MFA During Login vs Sensitive Actions

Sometimes MFA is required:

From the backend view, this means:

Simple examples:

Step-up Authentication

Step-up authentication means asking for more authentication when risk is higher.

Example:

This is useful when you do not want to ask for MFA every time, but you still want protection for critical operations.

Security Considerations and Best Practices

MFA is security sensitive, so the backend must follow some strict rules.

Rate Limits and Brute Force Protection

Attackers may try many MFA codes. You must limit attempts.

Typical protections:

For example:

Short Lifetimes

One time codes should expire quickly.

Typical settings:

Code typeLifetime
TOTP code30 seconds
SMS code3 to 10 minutes
Email code5 to 15 minutes
Challenge token5 to 15 minutes

Always set expiration times for MFA challenges and codes, and check them on the backend for every verification.

Never rely only on the frontend to hide old forms or messages.

Storage and Encryption

For TOTP:

For SMS / email codes:

Example model:

ColumnExample
iddf0481aa-...
user_id42
code_hashhash("928372")
expires_at2026-08-27T12:35Z
attempts_left3

You send only the code to the user, but the user must also send back the id or some token that lets you find the correct record.

Device and Session Binding

For some MFA methods, you should bind challenges to sessions or devices.

For example:

This prevents someone from using an MFA code from another device or from reusing an old challenge.

Backup Codes and Recovery

Users will lose their phones or change numbers. To avoid account lockout, you can offer backup codes.

These are one time codes generated in advance, for example 10 random strings like:

Backend behavior:

  1. Generate random backup codes.
  2. Show them to the user once, tell them to store them offline.
  3. Save only hashes of each code in the database.
  4. When a user uses a backup code, mark it as used.

Table example:

ColumnExample
user_id42
code_hashhash("BA9F-TK3D")
usedfalse

Rules:

UX Considerations That Affect Backend

User experience and backend security go together. Some backend decisions to improve UX:

Still, avoid leaking too much information. For example, do not say "Valid username but wrong MFA code" when revealing that a username exists is sensitive.

Putting It All Together: Example MFA Workflow

Here is a simple sequence for a TOTP MFA system on top of an existing password login.

1. Setup TOTP

  1. User opens "Enable MFA" page.
  2. Backend generates:
    • a random secret, base32 encoded
    • an otpauth:// URI
  3. Backend stores secret temporarily in a pending_mfa_setup record, bound to the user and an expiration.
  4. Backend returns the URI to client.
  5. Client shows QR code to user.
  6. User scans QR code and enters a 6 digit code from their app.
  7. Client sends code to /mfa/setup/confirm with a reference to the pending setup.
  8. Backend reads the secret from pending_mfa_setup.
  9. Backend computes TOTP and compares.
  10. If it matches:
    • move the secret to the permanent user record
    • mark mfa_enabled = true
  11. Delete pending_mfa_setup.

2. Login with MFA

  1. Client sends username and password to /login.
  2. Backend verifies password.
  3. If user does not have MFA:
    • backend issues normal session or JWT and login is complete.
  4. If user has MFA:
    • backend creates mfa_challenge with:
      • user_id
      • challenge_id or random token
      • created_at
      • expires_at, for example now + 5 minutes
    • backend returns:
      • HTTP 200 with
        • mfa_required: true
        • mfa_challenge_token: ...
        • optionally list of available methods
  5. Client shows "Enter your 6 digit code" screen.
  6. User enters code, client sends to /login/mfa/verify:
    • mfa_challenge_token
    • code
  7. Backend:
    • looks up mfa_challenge by token
    • checks expires_at
    • checks if already used
    • loads user and TOTP secret
    • verifies code for current time step
  8. If valid:
    • mark mfa_challenge as used
    • issue final session cookie or JWT
    • mark user session as mfa_verified_at = now
  9. If not valid:
    • decrement attempts counter
    • if attempts exceeded, delete challenge or lock it.

With this structure you separate:

This makes your system easier to test and maintain.

When and Where to Use MFA

In a backend application you are building in this course, you will normally add MFA in at least these areas:

MFA is not a silver bullet, but it significantly raises the cost for attackers. Combined with proper password hashing, secure session management, and other security practices from this course, it is a powerful part of a modern backend authentication system.

Views: 4

Comments

Please login to add a comment.

Don't have an account? Register now!