はじめに
前回、Auth0公式ReactクイックスタートにMFA(多要素認証)を追加してみたという記事で、「ログイン強化編」の2回目として、ログインのたびに常にMFAを要求する設定を試しました。
ただ、実際のサービスでは「全ユーザーに常にMFAを要求する」のはやや過剰で、ユーザー体験を損ねがちです。特に、前々回で追加したPasskeyは、生体認証とデバイス固有の鍵ペアによってフィッシング耐性を備えた認証方式であり、それ自体がすでに「もう一つの要素」に相当するとも言えます。
そこで今回は、Auth0 Actions を使って、ログイン方法に応じてMFAの要求を出し分けてみます。具体的には、
- Passkeyでログインした場合 → MFAをスキップ
- ID/パスワードでログインした場合 → MFAを要求
という条件分岐を実装します。これは認証後に実行されるAction(Post-Loginトリガー)の中で、「どの認証方法でログインしたか」というコンテキストを使って、MFAを要求するかどうかを動的に決める仕組みです。Auth0公式でも「Reduce friction with passkeys」というユースケースとして紹介されているパターンです。
※こちらの手順は2026年10月時点のものとなります。
事前準備
- 前回・前々回で作成したReactアプリ(
auth0-react-quickstart) - Passkeyが有効化されたAuth0のデータベース接続(前々回の記事参照)
- MFA(TOTPなど)が有効化されたAuth0テナント(前回の記事参照)
今回はダッシュボードの設定だけでなく、初めてActions(Node.jsのコード)を書きます。
1. 「ActionsでMFA要素をカスタマイズする」を有効化する
Actionsから api.multifactor.enable("none") などを呼び出してMFAの要求を制御するには、まずこの機能をダッシュボード側で有効にしておく必要があります。
これで、Actions側からMFAの要求有無をコントロールできるようになりました。
2. Actionを作成する
-
Auth0ダッシュボードの左メニューから 「アクション」→「ライブラリー」 を選択します。その後、カスタムタブの 「アクションの作成」 をクリックします。

-
初めから構築する を選択し、適当な名前(例:
skip-mfa-for-passkey)、トリガーは 「Login / Post Login」 を選択し、ランタイムはNode 22 を選択して作成します。

-
エディタに以下のコードを記述します。
/** * @param {Event} event - ログインしたユーザーとコンテキストの情報 * @param {PostLoginAPI} api - ログイン後の挙動を変更するためのAPI */ exports.onExecutePostLogin = async (event, api) => { // 今回の認証でPasskeyが使われたかどうかを判定する const usedPasskey = event.authentication?.methods.some( (method) => method.name === "passkey" ); // Passkeyでログインしていた場合はMFAをスキップする if (usedPasskey) { api.multifactor.enable("none"); } // ID/パスワードなど他の方法でログインした場合は何もしない // → テナントに設定済みの「常時」ポリシーがそのまま適用される };event.authentication.methodsには、今回のログインで使われた認証方法の履行履歴が配列で入っています。nameが"passkey"であれば、Passkeyでログインしたことがわかります。Passkeyが使われていた場合のみapi.multifactor.enable("none")を呼び、MFAを明示的にスキップします。ID/パスワードでログインした場合はこのActionは何もしないため、前回設定した「常時MFAを要求する」ポリシーがそのまま有効になります。 -
Auth0ダッシュボードの左メニューから 「アクション」→「トリガー」→「サインアップとログイン」→「post-login」 を選択します。

-
作成したActionをフロー図の 開始 と 完了 の間の位置にドラッグ&ドロップして追加し、「適用」 をクリックします。

これでログインの度に、このActionが実行されるようになりました。
3. 実際に動かしてみる
前回までに作成したReactアプリをそのまま起動します。
npm run dev
パターンA: Passkeyでログイン(MFAスキップを確認)
パターンB: ID/パスワードでログイン(MFA要求を確認)
同じアプリ・同じテナントでありながら、ログイン方法によってMFAの要求が自動的に出し分けられていることが確認できました。Reactアプリ側のコードは一切変更していません。
4. (応用編)APIのスコープに応じてMFAを要求する
今回は「ログイン方法」を条件にMFAを出し分けましたが、Actionsの event オブジェクトからは他にも様々なコンテキスト情報を参照できます。例えば、認可リクエストで要求されたスコープ(event.transaction.requested_scopes)を見て、機密性の高い操作に対応するスコープが要求された場合だけMFAを要求する、という組み方も可能です。
この例は、テナントのMFAポリシーが 「検証しない」 であることが前提です。前回設定した 「常時」 のままだと、すべてのログインでMFAが要求されるため、スコープによる絞り込みになりません。試す場合は、「セキュリティ」→「多要素認証」→「ポリシーを定義する」 でポリシーを「検証しない」に変更してください。なお、MFAが未登録のユーザーには、この例でもMFAの登録画面が表示されます。
exports.onExecutePostLogin = async (event, api) => {
const CLIENTS_WITH_MFA = ['REPLACE_WITH_{yourClientId}'];
if (CLIENTS_WITH_MFA.includes(event.client.client_id)) {
if (event.transaction.requested_scopes.indexOf('transfer:funds') > -1) {
api.multifactor.enable('any', { allowRememberBrowser: true });
}
}
};
これは「transfer:funds(送金)のスコープを要求しているクライアントからのログインにだけMFAを要求する」という例で、Auth0公式のステップアップ認証ドキュメントでも紹介されているパターンです。ログイン方法だけでなく、「どのAPI・どのスコープにアクセスしようとしているか」という情報もMFAの出し分けの条件に使えることがわかります。
まとめ
Auth0 Actionsを使って、ログイン方法に応じてMFAの要求を動的に出し分けてみました。
-
event.authentication.methodsから、ログインに使われた認証方法(Passkey / ID/パスワードなど)を判定できる -
api.multifactor.enable("none")を呼べば、特定の条件下でMFAをスキップできる - 逆に
api.multifactor.enable("any", ...)のように呼べば、特定の条件下でMFAを追加で要求することもできる - 条件には認証方法だけでなく、
event.transaction.requested_scopes(要求されたスコープ)なども使える - これらはダッシュボードの「ActionsでMFA要素をカスタマイズする」を有効化した上で、Reactアプリ側のコードを変更せずに実現できる
Passkeyのようなフィッシング耐性の高い認証方式を「もう一つの要素」とみなしてMFAをスキップする一方、相対的に弱いID/パスワード認証や、機密性の高い操作にはMFAを要求する。Actionsを使うことで、セキュリティとユーザー体験のバランスを、ユースケースに応じて柔軟に調整できることが確認できました。







