---
title: "Keycloak 認証フローの設定手順：ブラウザフロー複製と条件付きOTP・Required Actions"
url: "https://www.issoh.co.jp/tech/details/19386/"
published: 2026-11-06
updated: 2026-11-06
categories: ["セキュリティ"]
publisher: "株式会社一創"
---

# Keycloak 認証フローの設定手順：ブラウザフロー複製と条件付きOTP・Required Actions

Keycloakの認証フロー（Authentication Flows）は、ログイン画面でどの順に何を確かめるかを決める設定です。既定のままでは、ワンタイムパスワード（OTP）は認証アプリを登録した利用者にだけ求められ、未登録の利用者はパスワードだけで入れます。本記事では2026年11月6日時点の最新版Keycloak 26.8.2を前提に、既定のブラウザフローの読み方、複製して特定ロールの利用者だけOTPを必須にするkcadm.shのスクリプト、アプリ単位の上書き、Required ActionsでOTPの登録を求める設定を順に解説します。

## まとめ：Keycloakの認証フローは既定を複製して条件付きサブフローで組み替える

組み込みのブラウザフローは直接編集できないため、複製してから手を入れます。既定の「Browser – Conditional 2FA」は、OTPを登録済みの利用者にだけOTPを求める作りです。管理者など特定の利用者に必ずOTPを使わせたいなら、複製したフローにロール条件付きのサブフローを足し、OTPフォームをRequiredにします。未登録の対象者は、そのログインの途中でOTPの登録を求められます。

全員にOTPを求めるだけなら、フローの複製は不要です。Required Actionsの「Configure OTP」を既定アクションにし、既存ユーザーにも付ければ済みます。アプリ単位でフローを差し替える上書き設定は、SSO済みの利用者には効きません。管理画面だけ強い認証を求めたい場合は、ステップアップ認証で組みます。

## Keycloakの認証フローの構造と既定のブラウザフローでOTPが任意になる理由

ここで扱うのはKeycloakの管理画面にある「Authentication」の設定です。OIDCの仕様が定める認可コードフローやインプリシットフローとは別物で、そちらは[OIDCの認証フローとは](https://www.issoh.co.jp/tech/details/19354/)で解説しています。

### フロー・サブフロー・実行ステップの3層とRequirementの4つの評価規則

[Server Administration GuideのAuthentication flows](https://www.keycloak.org/docs/latest/server%5Fadmin/index.html#%5Fauthentication-flows)は、認証フローを、ログインや登録の際に行う認証・画面・処理の入れ物と説明しています。トップレベルのフローの中にサブフローと実行ステップ（Execution）が並び、サブフローの中にもさらに入れ子にできます。

各要素の動きは[Requirementの設定](https://www.keycloak.org/docs/latest/server%5Fadmin/index.html#%5Fexecution-requirements)で決まります。

| Requirement | 評価のされ方                   |
| ----------- | ------------------------ |
| Required    | 同じ階層の全てが順に成功する必要がある      |
| Alternative | どれか1つが成功すればよい            |
| Disabled    | 成功の判定に数えない               |
| Conditional | サブフロー専用・全条件が真でRequired扱い |

見落としやすいのは2点です。同じ階層にRequiredがあると、Alternativeの要素は実行されません。Conditionalのサブフローは、条件が1つでも偽になるか、条件が1つも置かれていない場合にDisabled扱いになります。

### 26.8.2の既定ブラウザフローの中身と2要素目が登録済みの利用者にだけ出る条件

既定のブラウザフローの構成は、[26.8.2のDefaultAuthenticationFlows.java](https://github.com/keycloak/keycloak/blob/26.8.2/server-spi-private/src/main/java/org/keycloak/models/utils/DefaultAuthenticationFlows.java)で確かめられます。新しいレルムに作られる並びは次のとおりです。

| 階層 | 実行ステップ・サブフロー              | 既定のRequirement |
| -- | ------------------------- | -------------- |
| 1  | Cookie                    | Alternative    |
| 1  | Kerberos                  | Disabled       |
| 1  | 外部IdPへのリダイレクト             | Alternative    |
| 1  | forms（サブフロー）              | Alternative    |
| 2  | Username Password Form    | Required       |
| 2  | Browser – Conditional 2FA | Conditional    |
| 3  | 利用者の設定済み条件                | Required       |
| 3  | Condition – credential    | Required       |
| 3  | OTP Form                  | Alternative    |
| 3  | WebAuthn Authenticator    | Disabled       |
| 3  | リカバリーコード入力フォーム            | Disabled       |

表内の「外部IdPへのリダイレクト」の正式名称はIdentity Provider Redirector、「利用者の設定済み条件」はCondition – user configured、「リカバリーコード入力フォーム」はRecovery Authentication Code Formです。OTPが任意になる理由は「Condition – user configured」による条件判定です。この条件は、同じサブフローの実行ステップが利用者向けに設定済みかを確かめるため、OTPを登録していない利用者では偽になり、2要素目の画面ごと飛ばされます。「Condition – credential」は、パスキー（パスワードレスのWebAuthn）でログインした場合に2要素目を省く条件で、パスキー機能が有効な場合だけ置かれます。WebAuthnを2要素目に使う設定は[WebAuthnとは](https://www.issoh.co.jp/tech/details/15375/)で扱いました。

## ブラウザフローを複製してロールを持つ利用者だけOTPを必須にするkcadm.shの設定

例として、レルム`corp`で、レルムロール`mfa-required`を持つ利用者にだけOTPを必ず使わせます。OTPを登録済みの一般の利用者には、既定どおりOTPを求めます。

### 組み込みフローを編集できない制約と複製したときに付くサブフロー名の規則

管理ガイドは、組み込みのフローは変更できず、要素のRequirementだけ変えられると書いています。[26.8.2のAuthenticationManagementResource.java](https://github.com/keycloak/keycloak/blob/26.8.2/services/src/main/java/org/keycloak/services/resources/admin/AuthenticationManagementResource.java)を読むと、組み込みのフローにステップやサブフローを足すAPIは400を返します。

複製のAPIで新しい名前を受け取るパラメーターは、`newName`です。中のサブフローは「新しい名前＋半角スペース＋元の名前」に改名されるため、`browser-mfa`として複製すると`browser-mfa forms`と`browser-mfa Browser - Conditional 2FA`ができます。スクリプトでサブフローを指定するときは、この名前をURLエンコードして使います。

### kcadm.shで条件付きサブフローとロール条件・OTPフォームを足すスクリプト

エンドポイントは[Admin REST API](https://www.keycloak.org/docs-api/latest/rest-api/index.html)の`authentication/flows`配下です。条件の設定キーは各Factoryクラスの定数で確かめました。

```
#!/usr/bin/env bash
# Keycloak 26.8 系：browser を複製し、mfa-required ロールの利用者だけ OTP を必須にする
# 前提：kcadm.sh と jq が使えること。ロール mfa-required は作成済み
set -euo pipefail
REALM=corp
FLOW=browser-mfa
FORMS="${FLOW}%20forms"
SUB_NAME="${FLOW} mfa-required-otp"
SUB="${FLOW}%20mfa-required-otp"

kcadm.sh config credentials --server https://auth.example.com --realm master --user admin

# 1. 既定の browser フローを複製する
kcadm.sh create authentication/flows/browser/copy -r "$REALM" -s newName="$FLOW"

# 2. forms の末尾に条件付きサブフローを足す（既定の Conditional 2FA より後ろに入る）
kcadm.sh create "authentication/flows/${FORMS}/executions/flow" -r "$REALM" \
  -s alias="$SUB_NAME" -s type=basic-flow -s description="mfa-required は OTP 必須"

# 3. サブフローに条件 2 つと OTP フォームを足す
for P in conditional-user-role conditional-sub-flow-executed auth-otp-form; do
  kcadm.sh create "authentication/flows/${SUB}/executions/execution" -r "$REALM" -s provider="$P"
done

# 4. 条件の設定（ロールを持つ、かつ既定の 2FA が実行されなかった場合だけ真）
exec_id() {
  kcadm.sh get "authentication/flows/$1/executions" -r "$REALM" \
    | jq -r --arg p "$2" '.[] | select(.providerId==$p or .displayName==$p) | .id'
}
kcadm.sh create "authentication/executions/$(exec_id "$SUB" conditional-user-role)/config" -r "$REALM" \
  -b '{"alias":"mfa-required-role","config":{"condUserRole":"mfa-required","negate":"false"}}'
kcadm.sh create "authentication/executions/$(exec_id "$SUB" conditional-sub-flow-executed)/config" -r "$REALM" \
  -b "{\"alias\":\"no-2fa-yet\",\"config\":{\"flow_to_check\":\"${FLOW} Browser - Conditional 2FA\",\"check_result\":\"not-executed\"}}"
```

手順4の2つ目の条件が要です。[Condition – sub-flow executed](https://github.com/keycloak/keycloak/blob/26.8.2/services/src/main/java/org/keycloak/authentication/authenticators/conditional/ConditionalSubFlowExecutedAuthenticatorFactory.java)に`not-executed`を指定すると、既定の2FAのサブフローが成功しなかった場合だけ真になります。これを入れないと、OTPを登録済みの対象者は2回OTPを聞かれます。この組み方は、管理ガイドの[2FA conditional workflow examples](https://www.keycloak.org/docs/latest/server%5Fadmin/index.html#twofa-conditional-workflow-examples)にある「OTP default」の例に、ロール条件を足したものです。

### 追加したステップの既定がDisabledになる仕様とRequirementの書き換え

APIで足したサブフローと実行ステップは、選べるRequirementが1つしかないものを除いて、Disabledで作られます。このままでは何も起きないので、次のように書き換えます。

```
# 5. Requirement を設定する（GET した要素を丸ごと送り返す）
set_req() {
  kcadm.sh get "authentication/flows/$1/executions" -r "$REALM" \
    | jq -c --arg p "$2" --arg r "$3" '.[] | select(.providerId==$p or .displayName==$p) | .requirement=$r' \
    | kcadm.sh update "authentication/flows/$1/executions" -r "$REALM" -n -f -
}
set_req "$FORMS" "$SUB_NAME" CONDITIONAL
set_req "$SUB" conditional-user-role REQUIRED
set_req "$SUB" conditional-sub-flow-executed REQUIRED
set_req "$SUB" auth-otp-form REQUIRED

# 6. レルムのブラウザフローを差し替える（動作確認の後に実行する）
kcadm.sh update realms/"$REALM" -s browserFlow="$FLOW"
```

idとrequirementだけを送る書き方は避けます。更新処理は`priority`の値も比べて書き換えるため、省くと並び順が変わるおそれがあります。`-n`は、取得と統合を省いてそのまま送る指定です。

OTPフォームをRequiredにした場合、OTPを登録していない対象者はログインの途中で登録画面に進みます。管理ガイドは、2要素目をRequiredにすると登録した直後の認証にその要素が使われない点を挙げ、1要素目にパスワードなどを置くよう求めています。この例はパスワードの後ろに置いているので、その条件を満たす構成です。

### ブラウザフローを割り当てる前に3種類の利用者で確かめる動作確認

手順6の割り当てを最後に回すのは、誤った設定のまま全員のログインを止めないためです。管理コンソールの`browser-mfa`の画面で並びとRequirementを確かめたら、検証用の利用者を3人用意します。

1. ロールなし・OTP未登録：パスワードだけでログインできる
2. ロールあり・OTP未登録：パスワードの後にOTPの登録画面が出る
3. ロールあり・OTP登録済み：OTPの入力が1回だけ求められる

3の利用者でOTPが2回出るなら、`flow_to_check`の名前が複製後のサブフロー名と一致していません。割り当て後に問題が出た場合は`browserFlow=browser`に戻せば、既定のフローに切り替わります。管理者自身がロックアウトされないよう、masterレルムの管理者で作業します。

## アプリ単位で認証フローを変えるクライアントの上書き設定と効かない場面

レルム全体ではなく、特定のアプリにだけ別のフローを使わせたい場面もあります。クライアントの詳細画面のAdvancedタブにある認証フローの上書きで設定します。

### クライアント単位の認証フロー上書きと名前ではなくIDを指定する設定

上書きはクライアントの`authenticationFlowBindingOverrides`に、種類ごとのフローのIDを入れる形で持ちます。種類のキーは`browser`と`direct_grant`の2つです。

```
# 管理画面のクライアント admin-portal だけ browser-mfa を使わせる
FID=$(kcadm.sh get authentication/flows -r corp | jq -r '.[] | select(.alias=="browser-mfa") | .id')
CID=$(kcadm.sh get clients -r corp -q clientId=admin-portal --fields id --format csv --noquotes)
kcadm.sh update clients/"$CID" -r corp -s "authenticationFlowBindingOverrides={\"browser\":\"$FID\"}"
```

値はフローの名前ではなくIDです。フローを作り直すとIDが変わるため、上書き側も入れ直します。クライアントの作成や更新をAPIで行う書き方は[Keycloak APIの使い方](https://www.issoh.co.jp/tech/details/19378/)にまとめました。

### 上書きしたフローがSSO済みの利用者に再認証を求めない理由とステップアップ

複製したフローの先頭にはCookieがAlternativeで残っています。管理ガイドによると、Cookieはセッションのクッキーがあれば成功し、同じ階層の他の要素は実行されません。つまり、別のアプリでパスワードだけでログインした利用者が管理画面を開くと、上書きしたフローを通っても、OTPを聞かれずに入れます。SSOの仕組み自体は[Keycloak SSOの設定手順](https://www.issoh.co.jp/tech/details/19384/)で説明しています。

アプリごとに認証の強さを変えたいなら、管理ガイドの[step-upの手順](https://www.keycloak.org/docs/latest/server%5Fadmin/index.html#%5Fstep-up-flow)で組みます。「Condition – Level of Authentication」で段階を分け、2段目にOTPフォームを置き、Max Ageを0にすると、その段階を要求したログインのたびにOTPを求められます。アプリは認可リクエストの`claims`または`acr_values`で段階を要求し、レルムの設定でACRの値と段階の数字を対応させる仕組みです。アプリを並べる時点で強さの違いが見えているなら、上書きよりステップアップで設計するほうが漏れません。

## Required ActionsでOTPの登録とパスワード変更を初回ログイン時に求める設定

認証フローが「ログインで何を確かめるか」を決めるのに対し、Required Actionsは「ログインの後に何をさせるか」を決めます。[管理ガイドのRequired actionsの節](https://www.keycloak.org/docs/latest/server%5Fadmin/index.html#con-required-actions%5Fserver%5Fadministration%5Fguide)は、資格情報を入れた後に実行させる操作と説明しています。

### 主なRequired Actionsの識別子と既定アクションが新規ユーザーにだけ効く範囲

| 画面の名前                | 識別子                    | 利用者にさせること    |
| -------------------- | ---------------------- | ------------ |
| Configure OTP        | CONFIGURE\_TOTP        | 認証アプリの登録     |
| Update Password      | UPDATE\_PASSWORD       | パスワードの変更     |
| Verify Email         | VERIFY\_EMAIL          | メールのリンクで所有確認 |
| Update Profile       | UPDATE\_PROFILE        | 氏名などの更新      |
| Terms and Conditions | TERMS\_AND\_CONDITIONS | 利用規約への同意     |

Required ActionsタブのSet as default actionを有効にすると、そのアクションは新しく作るユーザーに付きます。管理ガイドが対象として挙げるのは、管理画面のAdd userで作ったユーザーと、ログイン画面の登録リンクから作られたユーザーです。既に存在するユーザーには付かないため、次の項の一括付与が必要になります。

### 既存ユーザーにCONFIGURE\_TOTPを付けるkcadm.shのループと上書きの注意

```
# 新規ユーザーに OTP の登録を既定で求める
kcadm.sh update authentication/required-actions/CONFIGURE_TOTP -r corp -s enabled=true -s defaultAction=true

# 既存ユーザーにも付ける（requiredActions は配列ごと置き換わる点に注意）
for U in $(kcadm.sh get users -r corp --fields id --format csv --noquotes -l 1000); do
  kcadm.sh update users/"$U" -r corp -s 'requiredActions=["CONFIGURE_TOTP"]'
done
```

`requiredActions`は配列ごと置き換わるため、メール確認などが残っているユーザーでは元のアクションが消えます。運用中のレルムでは、先に各ユーザーの値を取得し、足してから送る手順が必要です。1,000人を超えるレルムでは`-o`と`-l`で区切って回します。

この方式とロール条件のフローでは、受け持つ役割が別々です。Required Actionsは1回登録させれば終わりで、毎回のOTP入力は既定の「Browser – Conditional 2FA」が受け持ちます。全員にOTPを使わせる方針なら、フローを複製せずこの方式で足ります。

### OTPポリシーの既定値6桁・30秒・SHA1と前後の時間ずれを許す窓

認証アプリの設定は、Authenticationの[OTP Policyタブ](https://www.keycloak.org/docs/latest/server%5Fadmin/index.html#one-time-password-otp-policies)で決めます。[26.8.2のOTPPolicy.java](https://github.com/keycloak/keycloak/blob/26.8.2/server-spi/src/main/java/org/keycloak/models/OTPPolicy.java)の既定値は、時刻ベースのTOTP・HmacSHA1・6桁・look around 1・30秒です。

管理ガイドによると、look aroundが1で30秒周期なら、前後を含めて90秒の範囲のコードを受け付けます。同じコードの再利用は既定で認められていません。ハッシュをSHA256以上に変える場合は、利用者が使う認証アプリが対応しているかを先に確かめます。総当たり対策の対象には、パスワードと並んでOTPとリカバリーコードが含まれます。

## 認証フローを作り込んだ後に運用で詰まる場面と既定のまま使う判断

認証フローは画面から自由に組めるぶん、作った後の保守が見落とされがちです。導入前に次の3点を決めておきます。

### 複製したフローはバージョンアップで既定の変更を取り込まないという保守の注意

複製したフローは、複製した時点の中身のまま残ります。管理ガイドの[Organizationsの既存フローの節](https://www.keycloak.org/docs/latest/server%5Fadmin/index.html#configuring-existing-authentication-flows)は、新しいレルムでは自動で足されるステップを、既存のカスタムフローには手で足すよう求めています。パスキー用の「Condition – credential」も、既定フローにだけ入る種類の変更です。

KeycloakはGitHubの公開日（UTC）で26.8.0が10月1日、26.8.1が10月13日、[26.8.2](https://github.com/keycloak/keycloak/releases/tag/26.8.2)が11月5日と、短い間隔で版が出ます。更新のたびに、新しいレルムの既定ブラウザフローと自社の複製フローを`kcadm.sh get authentication/flows/browser/executions`で並べて比べる手順を、更新作業の一覧に入れてください。更新の判断手順は[Keycloakの脆弱性対応の手順](https://www.issoh.co.jp/tech/details/19094/)で解説しています。

### ロール条件は1つしか指定できない制約と複合ロールで束ねる設計

Condition – user roleに入れられるロールは1つです。Keycloakのフォーラムでも、複数のロールを対象にできないという相談が出ています。ロールごとに条件付きサブフローを並べると、フローが読めなくなります。

対象を増やすときは、`mfa-required`のような判定専用のロールを1つ作り、管理者ロールや経理のグループにその複合ロールとして付けます。条件はユーザーが持つロールで判定されるため、グループ経由や複合ロール経由で付いたロールも判定結果は真です。条件の設定画面にある`negate`を使えば、「このロールを持つ人だけOTPを免除する」逆向きの指定もできます。

### カスタムAuthenticatorを書かずに済ませる条件と開発が必要になる場面

OTP・WebAuthn・リカバリーコードの組み合わせ、ロールや属性での分岐、未登録者の拒否までは、標準の実行ステップで組めます。管理ガイドには、2要素を使っていない利用者を「Deny Access」で止める例も載っています。この範囲でJavaのコードを書くのは過剰です。

一方、SMSでコードを送る、社内の勤怠システムの在籍情報で分岐する、といった要件は管理ガイドの手順に載っていません。この場合はAuthenticator SPIで実行ステップを自作し、Keycloakの版を上げるたびに再ビルドと検証を回す体制が要ります。2要素の方式選びから、フローの設計、カスタムAuthenticatorの開発と保守までまとめて任せたい場合は、一創の[認証基盤・ID管理システム開発](https://www.issoh.co.jp/service/system/identity/)で支援しています。

## Keycloakの認証フロー設定で導入担当者からよく受ける質問と回答

認証フローを組み替えるときに出やすい疑問をまとめました。

### 既定のブラウザフローで全員にOTPを必須にするにはどうしますか？

選択肢は、フローを複製する方法と、Required Actionsを使う方法の2つです。複製する場合は「Browser – Conditional 2FA」をRequiredに変え、中のOTP FormもRequiredにします。条件が評価されなくなるため、未登録の利用者はログインの途中で登録を求められます。新規ユーザーだけでなく既存ユーザーにも登録させたいなら、Configure OTPを既定アクションにして一括で付ける方法のほうが、フローを保守する手間がかかりません。

### OTPを登録していない管理者のログインを止めることはできますか？

できます。管理ガイドの「Conditional 2FA sub-flow and deny access」の例では、既定の2FAのサブフローの後ろに、Condition – sub-flow executedでnot-executedを判定するサブフローを置き、中にDeny Accessを入れます。本記事のスクリプトのOTPフォームをDeny Accessに置き換えれば、ロールを持つ未登録者はエラー画面で停止する動作です。エラーの文言は実行ステップの設定とログインテーマのメッセージで変えられます。ログインテーマの文言を上書きする手順は[Keycloak ログイン画面のカスタマイズ手順：テーマ作成・ロゴ差し替えと日本語メッセージの上書き](https://www.issoh.co.jp/tech/details/19390/)で扱いました。

### 外部IdPでログインした利用者にも認証フローは適用されますか？

外部IdPで認証した利用者は、ブラウザフローのパスワード欄の後ろに置いたOTPを通りません。戻った後に使われるのは、外部IdPの設定に紐づくFirst login flowとPost login flowです。外部IdPの多要素認証を信頼するなら追加の設定は要りません。Keycloak側でもOTPを求めたい場合は、OTPフォームだけを置いたフローを作り、外部IdPの設定のPost login flowに指定します。初回ログインでの既存アカウントとの紐付けは[Keycloak SAML設定：Entra IDを外部IdPにする手順](https://www.issoh.co.jp/tech/details/19370/)で扱いました。

### パスキーを導入するとOTPの認証フローはどう変わりますか？

既定のフローでは、パスキーでログインした利用者に2要素目を求めない「Condition – credential」が働きます。管理ガイドのpassword-less browser login flowの例は、パスキーとパスワード＋OTPを選べる構成です。Enable PasskeysとCondition – credentialの設定は[Keycloak パスキーの設定手順：Enable Passkeysとパスワードレスポリシー・登録の流れ](https://www.issoh.co.jp/tech/details/19388/)で扱いました。パスワードからパスキーへ段階的に切り替える進め方は[パスキー移行の実装手順](https://www.issoh.co.jp/tech/details/17716/)で解説しています。

### 作った認証フローを別の環境へ移すにはどうしますか？

フローはレルムの設定の一部なので、レルムのエクスポートに含まれます。ただし、実行ステップの設定にはIDが振られ、クライアントの上書きもフローのIDで持つため、環境ごとにIDが変わる点には注意が必要です。本記事のように名前で組み立てるスクリプトを用意しておけば、検証環境と本番に同じフローを再現できます。2要素認証の方式の違いや社内への説明の仕方は[二段階認証とは](https://www.issoh.co.jp/column/details/13268/)が参考になります。

## 関連記事

- [Keycloakとは？Oktaとの違いと連携手順｜Auth0・Cognito比較で導入を判断【2026年10月】](https://www.issoh.co.jp/tech/details/7663/)：Keycloakの機能の全体像と、Oktaなど他製品との違いです。
- [Keycloak SSOの設定手順：複数アプリのOIDCクライアント登録とセッション・ログアウト連携](https://www.issoh.co.jp/tech/details/19384/)：認証フローを通った後のSSOセッションとログアウトの設定です。
- [Keycloak APIの使い方：Admin REST APIでユーザー作成とロール付与をcurlで行う手順](https://www.issoh.co.jp/tech/details/19378/)：判定用ロールの付与をAPIで自動化する方法です。
- [WebAuthnとは？パスキー認証の仕組みと登録・認証フローをコードで解説](https://www.issoh.co.jp/tech/details/15375/)：OTPの代わりに2要素目に使える方式の仕組みです。
- [OIDCの認証フローとは？3つのフローとresponse\_typeの対応・移行判断を実装視点で解説](https://www.issoh.co.jp/tech/details/19354/)：名前が同じプロトコル側の認証フローの解説です。

---

出典: [Keycloak 認証フローの設定手順：ブラウザフロー複製と条件付きOTP・Required Actions](<https://www.issoh.co.jp/tech/details/19386/>)（株式会社一創）
