How to Set Up Multi-Factor Authentication (MFA) for Organizations in Logto

Logto enforces MFA for organization members by setting the is_mfa_required flag on the organization and configuring the global organizationRequiredMfaPolicy to Mandatory, which triggers the core MFA handler to verify bound factors before allowing sign-in.

Setting up multi-factor authentication (MFA) for organizations in Logto allows you to require that every member of a specific organization register an MFA factor before accessing protected resources. This feature is built on top of Logto’s existing MFA subsystem and is controlled through a combination of database-level flags and global sign-in experience policies. Whether you manage multi-tenant SaaS applications or need compliance-grade security for specific business units, organization-level MFA enforcement ensures that users cannot bypass secondary authentication when belonging to sensitive organizations.

Prerequisites

Logto introduced organization-level MFA enforcement in version 1.36.0. Ensure your deployment is running this version or later before configuring these settings, as the required database alterations (including the is_mfa_required column) are not present in earlier releases.

Understanding the Two-Layer Configuration

Organization MFA in Logto operates through two distinct configuration layers that must align for enforcement to trigger:

is_mfa_required on the Organization

organizationRequiredMfaPolicy in Sign-In Experience

When both the organization flag is true and the global policy is set to Mandatory, Logto’s core MFA class (packages/core/src/routes/experience/classes/mfa.ts) executes the isMfaRequiredByUserOrganizations method to validate that the user has at least one active MFA factor (TOTP, WebAuthn, or Backup Code).

Step-by-Step Setup Guide

Enable MFA Requirement on the Organization

You can toggle the MFA requirement using the Admin Console or the Management API. The UI toggle is implemented in packages/console/src/pages/Mfa/MfaForm/utils.ts, while the underlying state is stored in the is_mfa_required column of the organizations table.

Using the Management API:

curl -X PATCH "https://<logto-host>/api/organizations/<ORG_ID>" \
  -H "Authorization: Bearer <MANAGEMENT_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"isMfaRequired": true}'

Configure the Global MFA Policy

Set the organizationRequiredMfaPolicy to Mandatory in the sign-in experience configuration. This global setting is read from the sign_in_experiences table and validated by the mfaGuard in packages/schemas/src/foundations/jsonb-types/sign-in-experience.ts.

Using the Management API:

curl -X PATCH "https://<logto-host>/api/sign-in-experience" \
  -H "Authorization: Bearer <MANAGEMENT_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"mfa": {"organizationRequiredMfaPolicy": "Mandatory"}}'

If you prefer a hybrid approach where only specific organizations enforce MFA while others remain optional, keep the policy at NoPrompt and rely solely on the per-organization isMfaRequired flags.

Verify Enforcement

Sign in as a user who belongs to the organization. If the user has no MFA factors bound, Logto returns a 422 response with the error code session.mfa.require_mfa_verification. The front-end automatically redirects the user to the MFA setup page where they can enroll TOTP, WebAuthn, or backup codes.

How Organization MFA Enforcement Works

The Database Schema

The organizations table in packages/schemas/tables/organizations.sql defines the is_mfa_required boolean column. This column is checked during the authentication flow by queries located in packages/core/src/queries/organizations.ts.

The Core MFA Validation Logic

The enforcement logic resides in packages/core/src/routes/experience/classes/mfa.ts. When a user attempts to sign in, the system:

  1. Reads the organizationRequiredMfaPolicy from the sign-in experience settings
  2. Executes isMfaRequiredByUserOrganizations to check if the user belongs to any organization with is_mfa_required = true
  3. Calls getUserMfaFactors to verify active bound factors
  4. Throws a RequestError with session.mfa.require_mfa_verification if the user lacks MFA credentials

The Sign-In Experience Configuration

The mfa JSONB column in the sign_in_experiences table controls both the policy and available factors. You can restrict which MFA methods users may register by configuring the mfa.factors array:

curl -X PATCH "https://<logto-host>/api/sign-in-experience" \
  -H "Authorization: Bearer <MANAGEMENT_API_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"mfa": {"factors": ["Totp", "WebAuthn"]}}'

Code Examples

Enabling Organization MFA via Node.js SDK

import fetch from 'node-fetch';

const managementToken = '<MANAGEMENT_API_TOKEN>';
const orgId = '<ORG_ID>';
const logtoUrl = 'https://logto.example.com';

await fetch(`${logtoUrl}/api/organizations/${orgId}`, {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${managementToken}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ isMfaRequired: true }),
});

Setting the Mandatory Policy Programmatically

await fetch(`${logtoUrl}/api/sign-in-experience`, {
  method: 'PATCH',
  headers: {
    Authorization: `Bearer ${managementToken}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    mfa: {
      organizationRequiredMfaPolicy: 'Mandatory',
    },
  }),
});

Handling MFA Requirements in React Applications

import { useEffect } from 'react';
import { useLogto } from '@logto/react';

function MfaGuard() {
  const { getAccessToken } = useLogto();

  useEffect(() => {
    async function checkMfa() {
      const token = await getAccessToken();
      const response = await fetch('/api/me', {
        headers: { Authorization: `Bearer ${token}` },
      });
      const { mfaStatus } = await response.json();

      if (mfaStatus === 'needSetup') {
        window.location.href = '/mfa/setup';
      }
    }
    checkMfa();
  }, []);
}

Enrolling a TOTP Factor via API

curl -X POST "https://<logto-host>/api/my-account/mfa/totp" \
  -H "Authorization: Bearer <USER_ACCESS_TOKEN>" \
  -H "Content-Type: application/json" \
  -d '{"code":"123456"}'

Summary

  • Organization MFA requires two settings: the is_mfa_required flag on the organization table and the global organizationRequiredMfaPolicy set to Mandatory in the sign-in experience configuration.
  • Core enforcement happens in packages/core/src/routes/experience/classes/mfa.ts through the isMfaRequiredByUserOrganizations method, which queries the organizations table and validates bound MFA factors.
  • Configuration options include the Admin Console UI (packages/console/src/pages/Mfa/MfaForm/utils.ts) or direct Management API calls for automation.
  • Supported factors include TOTP, WebAuthn, and Backup Codes, configurable via the mfa.factors array in the sign-in experience settings.

Frequently Asked Questions

What Logto version supports organization-level MFA?

Organization-level MFA enforcement was introduced in Logto 1.36.0. Earlier versions lack the is_mfa_required column in the organizations table and the organizationRequiredMfaPolicy configuration option. Check your version by examining the alteration records or the logto_version metadata in your database.

What happens if a user belongs to multiple organizations with different MFA requirements?

Logto evaluates all organizations that the user belongs to during the sign-in process. If any organization has is_mfa_required = true and the global policy is set to Mandatory, the user must complete MFA verification regardless of other memberships. The isMfaRequiredByUserOrganizations method in packages/core/src/routes/experience/classes/mfa.ts performs this aggregate check.

Can I use the Admin Console instead of the Management API to configure MFA?

Yes. The Logto Admin Console provides a UI toggle for enabling organization MFA, implemented in packages/console/src/pages/Mfa/MfaForm/utils.ts. Navigate to the organization details page and enable the Require MFA switch. However, you must still configure the global organizationRequiredMfaPolicy to Mandatory via the Sign-in Experience settings to activate enforcement.

What MFA factors are supported for organization enforcement?

Logto supports TOTP (Time-based One-Time Password), WebAuthn (biometric/hardware keys), and Backup Codes for organization-level MFA. You can restrict which factors are available by modifying the mfa.factors array in the sign-in experience configuration. The validation logic in packages/core/src/routes/experience/classes/mfa.ts accepts any of these factors as satisfying the organization requirement.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →