ワンクリックで
use-case-mfa
MFA(多要素認証)ユースケースの設定ガイド。SMS/メール認証メソッド設定、MFA認証ポリシー(AND/OR/スコープ別)のヒアリングと設定JSONを提供。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
MFA(多要素認証)ユースケースの設定ガイド。SMS/メール認証メソッド設定、MFA認証ポリシー(AND/OR/スコープ別)のヒアリングと設定JSONを提供。
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
UserInfoエンドポイント(UserInfo Endpoint)機能の開発・修正を行う際に使用。UserInfo claims、scopeフィルタリング、verified_claims実装時に役立つ。
外部API認証ユースケースの設定ガイド。外部API連携(認証委譲、リスク判定、OTP等)の interaction 設計、identity_match_field、MFA 2段階目、previous_interaction のヒアリングと設定JSONを提供。
ユースケース別セットアップのエントリポイント。ユーザーにユースケースを選択してもらい、対応するスキル(use-case-login, use-case-mfa等)にルーティングする。共通ワークフロー、前提条件、組み合わせパターンの概要を提供。
認証機能(Authentication Policy, MFA)の開発・修正を行う際に使用。認証ポリシー、パスワード、OTP、FIDO2、条件付き認証実装時に役立つ。
セキュリティ・脆弱性対策の開発・テストを行う際に使用。OAuth/OIDC攻撃対策、認証識別子切り替え攻撃、Session Fixation、マルチテナント分離、セキュリティテスト実装時に役立つ。
外部サービス連携(External Service Integration)機能の開発・修正を行う際に使用。HTTP Request Executor, MappingRule, OAuth/HMAC認証実装時に役立つ。
| name | use-case-mfa |
| description | MFA(多要素認証)ユースケースの設定ガイド。SMS/メール認証メソッド設定、MFA認証ポリシー(AND/OR/スコープ別)のヒアリングと設定JSONを提供。 |
| # | 決めること | 選択肢 | 影響する設定 |
|---|---|---|---|
| 1 | 第2要素 | SMS / メール / 選択式 | 認証メソッド設定 |
| 2 | MFA適用範囲 | 全アプリ必須 / 特定アプリのみ / 特定スコープのみ | 認証ポリシー conditions, level_of_authentication_scopes |
| 3 | コード有効期限 | 3分 / 5分 / 10分 | 認証メソッド設定 metadata.expire_seconds |
| 4 | 試行回数上限 | 3回 / 5回 | 認証メソッド設定 metadata.retry_count_limitation |
| 5 | SMS/メール送信サービス | 外部API連携(Twilio等) / モック | 認証メソッド設定 interactions |
Email/SMS OTP認証は OTP管理(生成・検証・有効期限・リトライ制限)と メッセージ送信 の2層で構成される。
| execution.function | OTP管理 | メッセージ送信 | ユースケース |
|---|---|---|---|
email_authentication_challenge / sms_authentication_challenge | idp-server内部 | details.functionで選択 | 推奨(OTP管理が堅牢) |
http_request | 外部サービス丸投げ | 外部サービス丸投げ | 外部認証サービスが全責務を持つ場合 |
email_authentication_challenge / sms_authentication_challenge を使う場合、expire_seconds や retry_count_limitation は idp-server内部で強制 される。
http_request を使う場合、これらの設定はidp-serverでは効かず、外部サービス側の責務になる。
execution.function が email_authentication_challenge / sms_authentication_challenge の場合のみ有効。
| details.function | 送信方法 | 用途 |
|---|---|---|
no_action | 送信しない(ログのみ) | ローカル開発・テスト |
http_request | 外部API委譲(SendGrid/Twilio等) | 本番推奨 |
| ※Email限定: SMTP | idp-server内蔵SMTP送信 | Email のみ(metadata.settings.smtp で設定) |
Email認証:
| # | execution.function | details.function | OTP管理 | メール送信 |
|---|---|---|---|---|
| 1 | email_authentication_challenge | no_action | 内部 | 送信しない |
| 2 | email_authentication_challenge | http_request | 内部 | 外部API委譲 |
| 3 | http_request | — | 外部 | 外部 |
SMS認証:
| # | execution.function | details.function | OTP管理 | SMS送信 |
|---|---|---|---|---|
| 1 | sms_authentication_challenge | no_action | 内部 | 送信しない |
| 2 | sms_authentication_challenge | http_request | 内部 | 外部API委譲(#1394) |
| 3 | http_request | — | 外部 | 外部 |
{
"interactions": {
"email-authentication-challenge": {
"execution": {
"function": "email_authentication_challenge",
"details": {
"function": "http_request",
"sender": "noreply@example.com",
"sender_config": {
"http_request": {
"url": "https://api.sendgrid.com/v3/mail/send",
"method": "POST",
"header_mapping_rules": [
{ "static_value": "application/json", "to": "Content-Type" },
{ "static_value": "Bearer {API_KEY}", "to": "Authorization" }
],
"body_mapping_rules": [
{ "from": "$.request_body", "to": "*" }
]
}
},
"templates": {
"authentication": {
"subject": "Your verification code",
"body": "Code: {VERIFICATION_CODE}\nExpires in {EXPIRE_SECONDS}s."
}
},
"retry_count_limitation": 5,
"expire_seconds": 300
}
},
"response": {
"body_mapping_rules": [
{ "static_value": "sent", "to": "status", "condition": { "operation": "missing", "path": "$.error" } },
{ "from": "$.error", "to": "error", "condition": { "operation": "exists", "path": "$.error" } }
]
}
},
"email-authentication": {
"execution": {
"function": "email_authentication"
},
"response": {
"body_mapping_rules": [
{ "static_value": "verified", "to": "status", "condition": { "operation": "missing", "path": "$.error" } },
{ "from": "$.error", "to": "error", "condition": { "operation": "exists", "path": "$.error" } }
]
}
}
}
}
ポイント:
email-authentication-challenge の details 内に sender_config.http_request でHTTP送信先を設定email-authentication(検証)は execution.function = "email_authentication" のみ(内部検証、外部APIコール不要)retry_count_limitation と expire_seconds は details 内に設定し、idp-server内部で強制される| コンポーネント | クラス |
|---|---|
| OTP生成・検証(Email) | EmailChallengeAuthenticationExecutor, EmailAuthenticationExecutor |
| OTP生成・検証(SMS) | SmsChallengeAuthenticationExecutor, SmsAuthenticationExecutor |
| メール送信(no_action) | NoActionEmailSender |
| メール送信(HTTP) | HttpRequestEmailSender |
| SMS送信(no_action) | NoActionSmsSender |
| SMS送信(HTTP) | HttpRequestSmsSender(#1394) |
| 送信者選択 | EmailSenders.get(String function) / SmsSenders.get(SmsSenderType) |
| 設定読み込み | EmailAuthenticationConfiguration, EmailSenderConfiguration |
| 項目 | SMS | |
|---|---|---|
| idp-server 内蔵送信 | なし | あり(SMTP) |
| 外部API委譲 | http_request(Twilio等) | http_request(SendGrid等) |
| ローカル開発 | no_action(OTP生成のみ、送信なし) | no_action(OTP生成のみ、送信なし) |
http_request 委譲が必要metadata.settings.smtp)を行えば idp-server 単体でメール送信可能。外部API委譲も選択可API: POST /v1/management/organizations/{org-id}/tenants/{tenant-id}/authentication-configurations
パターン選択: 下記は外部丸投げ(
execution.function = "http_request")パターン。 内部OTP管理 + 外部SMS送信パターンは「OTP認証の2層アーキテクチャ」セクションを参照。
{
"id": "{uuid}",
"type": "sms",
"metadata": {
"type": "external",
"description": "SMS authentication for MFA",
"transaction_id_param": "transaction_id",
"verification_code_param": "verification_code",
"retry_count_limitation": 5,
"expire_seconds": 300
},
"interactions": {
"sms-authentication-challenge": {
"request": {
"schema": {
"type": "object",
"properties": {
"phone_number": { "type": "string" },
"template": { "type": "string" }
}
}
},
"execution": {
"function": "http_request",
"http_request": {
"url": "{SMS送信サービスURL}",
"method": "POST",
"auth_type": "oauth2",
"oauth_authorization": {
"type": "password",
"token_endpoint": "{認証トークンエンドポイント}",
"client_id": "{client_id}",
"username": "{username}",
"password": "{password}",
"scope": "application"
},
"header_mapping_rules": [
{ "static_value": "application/json", "to": "Content-Type" }
],
"body_mapping_rules": [
{ "from": "$.request_body", "to": "*" }
]
},
"http_request_store": {
"key": "sms-authentication-challenge",
"interaction_mapping_rules": [
{ "from": "$.response_body.transaction_id", "to": "transaction_id" }
]
}
},
"response": {
"body_mapping_rules": [
{ "from": "$.execution_http_request.response_body.status", "to": "status" },
{ "from": "$.execution_http_request.response_body.message", "to": "message", "condition": { "operation": "exists", "path": "$.execution_http_request.response_body.message" } },
{ "from": "$.execution_http_request.response_body.error", "to": "error", "condition": { "operation": "exists", "path": "$.execution_http_request.response_body.error" } },
{ "from": "$.execution_http_request.response_body.error_description", "to": "error_description", "condition": { "operation": "exists", "path": "$.execution_http_request.response_body.error_description" } }
]
}
},
"sms-authentication": {
"request": {
"schema": {
"type": "object",
"properties": {
"verification_code": { "type": "string" }
}
}
},
"execution": {
"function": "http_request",
"previous_interaction": {
"key": "sms-authentication-challenge"
},
"http_request": {
"url": "{SMS検証サービスURL}",
"method": "POST",
"auth_type": "oauth2",
"oauth_authorization": {
"type": "password",
"token_endpoint": "{認証トークンエンドポイント}",
"client_id": "{client_id}",
"username": "{username}",
"password": "{password}",
"scope": "application"
},
"header_mapping_rules": [
{ "static_value": "application/json", "to": "Content-Type" }
],
"body_mapping_rules": [
{ "from": "$.request_body", "to": "*" },
{ "from": "$.interaction.transaction_id", "to": "transaction_id" }
]
}
},
"response": {
"body_mapping_rules": [
{ "from": "$.execution_http_request.response_body.status", "to": "status" },
{ "from": "$.execution_http_request.response_body.message", "to": "message", "condition": { "operation": "exists", "path": "$.execution_http_request.response_body.message" } },
{ "from": "$.execution_http_request.response_body.error", "to": "error", "condition": { "operation": "exists", "path": "$.execution_http_request.response_body.error" } },
{ "from": "$.execution_http_request.response_body.error_description", "to": "error_description", "condition": { "operation": "exists", "path": "$.execution_http_request.response_body.error_description" } }
]
}
}
}
}
ヒアリング結果の反映先:
| ヒアリング項目 | JSONキー | 値の例 |
|---|---|---|
| コード有効期限(秒) | metadata.expire_seconds | 180, 300, 600 |
| 試行回数上限 | metadata.retry_count_limitation | 3, 5 |
| SMS送信サービスURL | interactions.sms-authentication-challenge.execution.http_request.url | Twilio API等 |
| SMS検証サービスURL | interactions.sms-authentication.execution.http_request.url | Twilio API等 |
API: POST /v1/management/organizations/{org-id}/tenants/{tenant-id}/authentication-configurations
パターン選択: 下記は外部丸投げ(
execution.function = "http_request")パターン。 内部OTP管理 + 外部メール送信パターンは「OTP認証の2層アーキテクチャ」セクションを参照。 内部OTP管理を使う場合、expire_secondsとretry_count_limitationはidp-server内部で強制される。
{
"id": "{uuid}",
"type": "email",
"metadata": {
"type": "external",
"sender": "{送信元メールアドレス}",
"retry_count_limitation": 5,
"expire_seconds": 300,
"settings": {
"smtp": {
"host": "{SMTPホスト}",
"port": 587,
"username": "{SMTPユーザー}",
"password": "{SMTPパスワード}",
"auth": true,
"starttls": { "enable": true }
}
}
},
"interactions": {
"email-authentication-challenge": {
"execution": {
"function": "http_request",
"http_request": {
"url": "{メール送信サービスURL}",
"method": "POST",
"auth_type": "oauth2",
"oauth_authorization": {
"type": "password",
"token_endpoint": "{認証トークンエンドポイント}"
}
}
}
}
}
}
API: POST /v1/management/organizations/{org-id}/tenants/{tenant-id}/authentication-policies
パターンA: パスワード + SMS(AND必須):
{
"flow": "oauth",
"enabled": true,
"policies": [
{
"description": "password + sms mfa",
"priority": 1,
"conditions": {},
"available_methods": ["password", "sms", "initial-registration"],
"success_conditions": {
"any_of": [
[
{ "path": "$.password-authentication.success_count", "type": "integer", "operation": "gte", "value": 1 },
{ "path": "$.sms-authentication.success_count", "type": "integer", "operation": "gte", "value": 1 }
],
[
{ "path": "$.initial-registration.success_count", "type": "integer", "operation": "gte", "value": 1 },
{ "path": "$.sms-authentication.success_count", "type": "integer", "operation": "gte", "value": 1 }
]
]
}
}
]
}
パターンB: パスワード + (SMS or メール)(選択式MFA):
{
"flow": "oauth",
"enabled": true,
"policies": [
{
"description": "password + (sms or email)",
"priority": 1,
"conditions": {},
"available_methods": ["password", "sms", "email", "initial-registration"],
"success_conditions": {
"any_of": [
[
{ "path": "$.password-authentication.success_count", "type": "integer", "operation": "gte", "value": 1 },
{ "path": "$.sms-authentication.success_count", "type": "integer", "operation": "gte", "value": 1 }
],
[
{ "path": "$.password-authentication.success_count", "type": "integer", "operation": "gte", "value": 1 },
{ "path": "$.email-authentication.success_count", "type": "integer", "operation": "gte", "value": 1 }
]
]
}
}
]
}
パターンC: 特定スコープでのみMFA必須:
{
"flow": "oauth",
"enabled": true,
"policies": [
{
"description": "mfa_for_transfers_scope",
"priority": 10,
"conditions": { "scopes": ["transfers"] },
"available_methods": ["password", "sms"],
"success_conditions": {
"any_of": [
[
{ "path": "$.password-authentication.success_count", "type": "integer", "operation": "gte", "value": 1 },
{ "path": "$.sms-authentication.success_count", "type": "integer", "operation": "gte", "value": 1 }
]
]
}
},
{
"description": "password_only_default",
"priority": 1,
"conditions": {},
"available_methods": ["password"],
"success_conditions": {
"any_of": [
[
{ "path": "$.password-authentication.success_count", "type": "integer", "operation": "gte", "value": 1 }
]
]
}
}
]
}
重要: この設定が無いと UserInfo / ID Token が
subのみしか返さない。 詳細はuse-case-loginスキルの「クレーム設定」セクションを参照。
認可サーバーの claims_supported に返したいクレーム一覧を設定する。
標準的な設定は config/templates/tenant-template.json を参照。
詳細は
spec-external-integrationスキルの「認証設定の内部/外部で異なるマッピングパス」を参照。
| 項目 | 内部ビルトイン (email_authentication_challenge 等) | 外部 HTTP (http_request) |
|---|---|---|
| response のマッピングパス | $ (executor contents 直接) | $.execution_http_request.response_body |
| 送信ボディで前のインタラクション参照 | N/A | $.interaction.xxx |
ワイルドカード "to": "*" | 内部データ漏洩リスク(verification_code 等) | 外部レスポンス丸ごと漏洩リスク |
| 推奨 | static_value + 条件付きエラーマッピング | 必要フィールドだけ明示的にマッピング |
認証ポリシーの step_definitions でステップの実行順序とユーザー特定方法を定義する。
| フィールド | 説明 |
|---|---|
method | 認証メソッド名(password, email, sms, fido2 等) |
order | 実行順序(1が最初) |
requires_user | true: 前のステップで既にユーザーが特定されていることが前提。false: このステップ自身がユーザーを特定する |
user_identity_source | requires_user: false の場合に必要。どのフィールドでユーザーを特定するか("email", "username" 等) |
重要: 最初のステップ(order=1)には必ず
requires_user: false+user_identity_sourceを設定すること。requires_user: trueを最初のステップに設定すると、まだユーザーが特定されていないためuser_not_foundエラーになる。
例: Email → Password(デフォルト):
"step_definitions": [
{ "method": "email", "order": 1, "requires_user": false, "user_identity_source": "email" },
{ "method": "password", "order": 2, "requires_user": true }
]
例: Password → Email(順序反転):
"step_definitions": [
{ "method": "password", "order": 1, "requires_user": false, "user_identity_source": "username" },
{ "method": "email", "order": 2, "requires_user": true }
]
注意:
conditionsとsuccess_conditionsは構造が異なる。混同しないこと。
どのリクエストにこのポリシーを適用するかを決める。専用フィールドで指定する:
// スコープ条件: transfers スコープを要求した場合のみ適用
"conditions": { "scopes": ["transfers"] }
// 無条件(全リクエストに適用)
"conditions": {}
NG: conditions に any_of + JSONPath を使うのは誤り。それは success_conditions の構造。
重要: priority とconditions の関係
conditions.scopesが空[]のポリシーは全リクエストにマッチする- マッチした全ポリシーの中から priority が最も高いものが選択される
- そのため、スコープ条件付きポリシーは、デフォルトポリシーよりも priority を高く 設定すること
- 例:
mfa_for_transfers(priority: 10) >password_only(priority: 1)
認証が成功したと判定する条件。any_of + JSONPath で指定する:
| 要件 | any_of構造 | 意味 |
|---|---|---|
| AND(MFA必須) | [[条件1, 条件2]] | 両方成功が必要 |
| OR(選択式) | [[条件1], [条件2]] | いずれか1つでOK |
| AND+OR(選択式MFA) | [[条件1, 条件2], [条件1, 条件3]] | (1+2) OR (1+3) |
$.password-authentication.success_count
$.sms-authentication.success_count
$.email-authentication.success_count
$.fido2-authentication.success_count
$.fido-uaf-authentication.success_count
$.initial-registration.success_count
$.password-authentication.failure_count
| # | 確認観点 | 設定箇所 | よくあるミス |
|---|---|---|---|
| 1 | claims_supported が設定済み | 認可サーバー | 未設定で UserInfo/ID Token が sub のみ |
| 2 | ui_config.base_url が認証UIのオリジン | テナント ui_config | APIサーバーURLを設定してしまう |
| 3 | cors_config に全フィールド設定 | テナント cors_config | allow_origins だけで allow_headers, allow_methods, allow_credentials が抜ける |
| 4 | email/SMS認証設定が存在する | authentication-config | 未作成で Authentication Configuration Not Found エラー |
| 5 | 認証ポリシーの success_conditions がAND条件 | 認証ポリシー | [[条件1, 条件2]](AND)ではなく [[条件1], [条件2]](OR)にしてしまう |
| 6 | failure_conditions / lock_conditions 設定済み | 認証ポリシー | 未設定だと認証失敗でアカウントロックされない |
| 7 | no-actionモードの場合、Management APIで検証コード取得可能 | 動作確認手順 | 管理者トークンのスコープに management が含まれていない |
| 8 | 最初のステップに requires_user: false + user_identity_source | step_definitions | 最初のステップに requires_user: true を設定して user_not_found エラー |
MFA が正しく実行されたかは ID Token の amr クレームで確認できる:
echo "${ID_TOKEN}" | cut -d'.' -f2 | python3 -c "import sys,base64,json; print(json.dumps(json.loads(base64.urlsafe_b64decode(sys.stdin.read().strip()+'==')),indent=2))"
amr に ["email", "password"] のように両方の認証方式が含まれていればMFA成功| テスト | prompt値 | 目的 |
|---|---|---|
| ユーザー登録 | prompt=create | Sign Up画面を直接表示 |
| MFA再認証 | prompt=login | 既存セッションを無視してMFA認証を再実行 |
config/templates/use-cases/mfa-email/config/examples/e2e/.../authentication-config/sms/external.jsonconfig/examples/e2e/.../authentication-config/email/smtp.jsonconfig/examples/e2e/.../authentication-policy/oauth.jsondocumentation/docs/content_05_how-to/phase-2-security/01-mfa-setup.mddocumentation/docs/content_05_how-to/phase-1-foundation/07-authentication-policy.mddocumentation/docs/content_05_how-to/phase-2-security/03-authentication-policy-advanced.md — conditions(scopes, client_ids)、failure_conditions、lock_conditions、step_definitions の詳細documentation/docs/content_06_developer-guide/05-configuration/authentication-policy.md — 設定リファレンスdocumentation/docs/content_02_quickstart/quickstart-05-mfa.md$ARGUMENTS