Azure Static Web Apps で Azure AD (login.microsoftonline.com) から Microsoft Entra External ID (CIAM / ciamlogin.com) に切り替えた途端、ログインは成功しているのにアプリ側ではサインイン画面に戻され続ける――そんな「認証ループ」で詰まっていませんか。本記事では、原因と具体的な解決手順を、staticwebapp.config.json のサンプルとともに詳しく解説します。
Azure Static Web Apps と Entra External ID (CIAM) 移行後に起きる認証ループとは
まず、どんな現象が発生しているかを整理します。
- 従来:Azure AD テナント(
login.microsoftonline.com)に対して、SWA の組み込みazureActiveDirectoryプロバイダーで正常にログインできていた。 - 移行後:Microsoft Entra External ID (CIAM) テナント(
*.ciamlogin.com)に切り替えたところ、- サインイン画面で ID/パスワード入力
- MFA も成功と表示
- しかしアプリ側には戻らず、再度サインイン画面にリダイレクトされる
- このサイクルが永遠に続く(リダイレクト・ループ)
- Azure ポータルのログを見ると「ログイン成功」と出ているため、どこが悪いのか分かりにくい。
多くの方は、staticwebapp.config.json の openIdIssuer だけを CIAM のエンドポイントに変える、という対応を取ります。
{
"auth": {
"identityProviders": {
"azureActiveDirectory": {
"registration": {
"openIdIssuer": "https://<tenant-name>.ciamlogin.com/<tenant-id>/v2.0",
"clientIdSettingName": "AZURE_CLIENT_ID",
"clientSecretSettingName": "AZURE_CLIENT_SECRET"
}
}
}
}
}
しかし、これだけでは CIAM では動きません。理由は、CIAM テナント (ciamlogin.com) が Azure Static Web Apps の「組み込み」Azure AD プロバイダーではサポートされておらず、カスタム OpenID Connect プロバイダーとして構成する必要があるためです。
なぜ Azure AD では動いていたのに CIAM でループするのか
ポイントは以下の 2 つです。
- 組み込み
azureActiveDirectoryプロバイダーは、Microsoft Entra ID(従業員向けテナント)向けに最適化されている。 - CIAM テナントは
ciamlogin.comドメインを使う別系統のサービスであり、トークンの発行元 (issuer) やクレームの扱いが一部異なる。
Azure Static Web Apps の公式ドキュメントでも、カスタム OpenID Connect プロバイダーを使う場合は auth.identityProviders.customOpenIdConnectProviders を使うことが明記されています。
Microsoft Q&A でも、CIAM テナントで組み込み azureActiveDirectory を使おうとして認証ループに陥った事例が報告されており、公式モデレーターから「CIAM テナント (ciamlogin.com) は built-in AAD プロバイダーではサポートされない。customOpenIdConnectProviders で構成してほしい」と回答されています。
つまり、設定ミスというよりは構成方式そのものが間違っている、というのが最大の原因です。
| 項目 | 従来 Azure AD テナント | Entra External ID (CIAM) テナント |
|---|---|---|
| Issuer ドメイン | login.microsoftonline.com | <tenant>.ciamlogin.com |
| SWA 側プロバイダー | azureActiveDirectory (組み込み) | customOpenIdConnectProviders (カスタム) |
| ログイン URL 例 | /.auth/login/aad | /.auth/login/ciam (ラベルに依存) |
| 典型的な失敗パターン | Issuer URL のタイポ等 | 組み込み AAD のまま CIAM を指す → ループ |
解決の全体像
大枠の解決ステップは次のとおりです。
- staticwebapp.config.json で CIAM をカスタム OIDC プロバイダーとして定義する。
- CIAM テナント側で リダイレクト URI(コールバック)を
/.auth/login/プロバイダー名/callbackまで含めて完全一致で登録する。 /.auth/*へのアクセスを anonymous で許可し、それ以外のパスを authenticated に制限する。- カスタムドメインを使う場合は staticwebapps.net とカスタムドメインの両方のコールバック URI を登録する。
/.auth/login/ciam?post_login_redirect_uri=/などで動作確認し、/.auth/meでクレームが取れることを確認する。
順番に見ていきます。
staticwebapp.config.json の最小構成例
CIAM を使った最小構成の例です。プロバイダー名として ciam を選んでいますが、任意のラベルを付けられます。このラベル名がログイン URL およびコールバック URL にそのまま反映されます。
{
"routes": [
{
"route": "/.auth/*",
"allowedRoles": [ "anonymous" ]
},
{
"route": "/*",
"allowedRoles": [ "authenticated" ]
}
],
"responseOverrides": {
"401": {
"statusCode": 302,
"redirect": "/.auth/login/ciam"
}
},
"auth": {
"identityProviders": {
"customOpenIdConnectProviders": {
"ciam": {
"registration": {
"clientIdSettingName": "AZURE_CLIENT_ID",
"clientSecretSettingName": "AZURE_CLIENT_SECRET",
"openIdConnectConfiguration": {
"wellKnownOpenIdConfiguration": "https://<tenant-name>.ciamlogin.com/<tenant-id>/v2.0/.well-known/openid-configuration"
}
}
/* "login": { "scopes": ["openid","profile","email"] } は省略可(後述) */
}
}
}
}
}
ここでのポイントは次の通りです。
/.auth/*を anonymous にしていること。- このパスを塞いでしまうと、SWA 自身が認証フローを完結できず、結果として認証ループになります。
- 401 は
/.auth/login/ciamに 302 リダイレクトしていること。- 未認証ユーザーのアクセスを CIAM ログインに誘導します。
customOpenIdConnectProvidersにciamというラベル名でプロバイダーを登録していること。- ログイン URL は
/.auth/login/ciam、コールバックは/.auth/login/ciam/callbackになります。
- ログイン URL は
wellKnownOpenIdConfigurationは Issuer URL +/.well-known/openid-configuration- CIAM の場合は
https://<tenant-name>.ciamlogin.com/<tenant-id>/v2.0/.well-known/openid-configurationという形になります。
- CIAM の場合は
clientSecretSettingName の位置について
上の例では、clientSecretSettingName を registration 直下に書いています。この形式は、ほかの組み込みプロバイダー(GitHub、Google 等)でも採用されているシンプルな形です。
Azure の公式ドキュメントには、カスタム OIDC プロバイダーの例として、以下のように clientCredential オブジェクトを挟むスタイルも記載されています。
"registration": {
"clientIdSettingName": "MY_PROVIDER_CLIENT_ID",
"clientCredential": {
"clientSecretSettingName": "MY_PROVIDER_CLIENT_SECRET_APP_SETTING_NAME"
},
"openIdConnectConfiguration": {
"wellKnownOpenIdConfiguration": "https://<PROVIDER_ISSUER_URL>/.well-known/openid-configuration"
}
}
どちらの書き方もサポートされていますが、
- プロパティ名のスペルミス
- 余計な階層を作ってしまう(例:
clientCredentialsなど、微妙なタイポ)
といったミスがあると、SWA がクライアントシークレットを解決できず、トークン検証に失敗 → 認証ループという症状につながります。特に CIAM を初めて試すときは、まずはシンプルな clientSecretSettingName 直下のパターンで動作確認することをおすすめします。
ログイン URL とコールバック URL の対応表
| 設定上のラベル名 | ログイン URL | コールバック URL |
|---|---|---|
"ciam" | /.auth/login/ciam | /.auth/login/ciam/callback |
"aadb2c"(B2C の例) | /.auth/login/aadb2c | /.auth/login/aadb2c/callback |
この「ラベル名 = パスの一部」というルールを忘れて、CIAM 側に /aad/callback を登録してしまうケースが非常に多いので注意してください。
CIAM(Entra External ID)側の設定ポイント
次に、Microsoft Entra External ID (CIAM) テナント側での設定を整理します。
アプリ登録(Web アプリとして登録)
- CIAM テナントの Azure ポータルで「アプリの登録」を作成します(Web アプリ)。
- プラットフォームに 「Web」 を追加し、リダイレクト URI を以下のように設定します。
https://<your-app>.staticwebapps.net/.auth/login/ciam/callback- カスタムドメインを使う場合:
https://<your-custom-domain>/.auth/login/ciam/callback
- 「アプリケーション (クライアント) ID」とクライアントシークレットを控え、SWA のアプリ設定に
AZURE_CLIENT_IDAZURE_CLIENT_SECRET
CIAM で Google や Microsoft アカウントなど外部 ID プロバイダー(IdP)とフェデレーションしている場合は、各 IdP 側の開発者ポータルでも同じコールバック URI を登録する必要があります(CIAM のアプリ単体だけ登録しても戻ってきません)。
スコープ設定について
OpenID Connect の標準スコープである openid, profile, email は、Azure Static Web Apps のカスタム OIDC プロバイダーで既定で要求されます。
そのため、staticwebapp.config.json の login.scopes に明示的に書かなくても基本的には問題ありません。トラブルシューティングの観点からも、まずは余計なカスタマイズを入れずに既定動作で動かしてみるのが安全です。
"login": {
"scopes": ["openid", "profile", "email"]
}
上記のように指定しても悪さをすることはほぼありませんが、「スコープを明示すればループが直る」類の問題ではないことは押さえておきましょう。
Issuer / メタデータの確認
CIAM の OIDC メタデータは、以下の URL から取得できます。
https://<tenant-name>.ciamlogin.com/<tenant-id>/v2.0/.well-known/openid-configuration
ブラウザや curl でこの URL を開き、返却される JSON 内の issuer が、SWA 側の openIdConnectConfiguration の Issuer と完全一致しているか確認します。
認証ループの典型原因とチェックリスト
ここからは、よくある「ループ」の原因と、その切り分けポイントを整理します。
1. プロバイダー種別の不一致
最も多いのが、組み込み azureActiveDirectory プロバイダーのまま CIAM テナントを指しているパターンです。
- 症状:
- MFA まで成功するが、アプリに戻った瞬間にまたサインイン画面へ。
- SWA のログでは「ログイン成功」と見えることもある。
- 対処:
azureActiveDirectoryのブロックを削除し、customOpenIdConnectProviders.ciamを定義し直す。
2. コールバック URI とラベル名の不一致
staticwebapp.config.json では "ciam" というラベル名を使っているのに、CIAM 側では /.auth/login/aad/callback を登録してしまっている、というケースです。
この場合、
- CIAM 側からは
/aad/callbackにトークンを返しているのに、 - SWA 側は
/ciam/callbackを待っている
という食い違いが起きます。結果的に トークンが正しく処理されず、未認証扱い → 401 → 再ログインとなり、ループになります。
3. /.auth/* をブロックしてしまっている
次に多いのが、routes で「全て認証必須」にした結果、/.auth/* まで塞いでしまうパターンです。
"routes": [
{
"route": "/*",
"allowedRoles": [ "authenticated" ]
}
]
この設定だと、
- 未認証ユーザーが
/.auth/login/ciamにアクセス → 401 - 401 の結果、responseOverrides でまた
/.auth/login/ciamに飛ばす → 401 →…
という具合に「ログインエンドポイントにすら到達できないループ」になります。
必ず以下のように、/.auth/* だけは anonymous にしておきましょう。
"routes": [
{
"route": "/.auth/*",
"allowedRoles": [ "anonymous" ]
},
{
"route": "/*",
"allowedRoles": [ "authenticated" ]
}
]
4. ドメインの不一致(特にカスタムドメイン)
認証クッキーはドメインに紐づくため、
- ログインは
https://<your-app>.staticwebapps.netで行っているが、 - アプリのアクセスは
https://example.com(カスタムドメイン)で行っている
というように、ログインとアプリ利用でドメインが分裂していると、クッキーが有効に機能せず、結果的にループになります。
この問題を避けるには、
- CIAM アプリ登録で
https://<your-app>.staticwebapps.net/.auth/login/ciam/callbackhttps://<your-custom-domain>/.auth/login/ciam/callback
- 本番では極力カスタムドメイン側で完結させるよう運用を揃える。
5. Issuer / well-known URL の誤り
CIAM の Issuer URL は、微妙な末尾のスラッシュや /v2.0 の有無で間違えやすいポイントです。
.../v2.0が抜けている- テナント ID とテナント名(ドメイン)の位置を取り違えている
- 最後に余計なスラッシュが付いている
といった誤りがあると、SWA 側で「issuer mismatch」と判断され、認証は成功しているように見えてもクッキーが発行されず、ループします。
必ず、メタデータの issuer 値と完全一致する形で設定しましょう。
6. ブラウザのクッキー・セッションの残骸
構成を何度も変えながら試していると、ブラウザ側に古いセッション情報やクッキーが残っていて、動作確認の妨げになることがあります。
- ブラウザのクッキー/サイトデータを削除する
- シークレットウィンドウ(InPrivate/プライベートブラウズ)で試す
- 別ブラウザでも再現するか確認する
といった基本的な切り分けも忘れずに行いましょう。
動作確認の具体的な手順
設定を変えた後は、以下の手順で「どこまでうまく動いているか」を確認します。
1. 直接ログイン URL を叩く
ブラウザで次の URL を開きます。
https://<your-app>.staticwebapps.net/.auth/login/ciam?post_login_redirect_uri=/
ここで CIAM のログイン画面 → MFA → アプリトップ(/)まで戻ってくれば、少なくとも
- CIAM との連携
- リダイレクト URI
までは正しく設定されていると考えられます。
2. /.auth/me でクレームを確認する
ログインした状態で、別タブから /.auth/me にアクセスします。
https://<your-app>.staticwebapps.net/.auth/me
もしくは、ブラウザのコンソールで次の JavaScript を実行してもかまいません。
async function getUserInfo() {
const response = await fetch('/.auth/me');
const payload = await response.json();
return payload.clientPrincipal;
}
getUserInfo().then(console.log);
clientPrincipal にメールアドレス等のクレームが入っていれば、クッキーが正しく設定され、SWA が認証状態を認識できていると判断できます。ここで空配列や null になっている場合は、クッキー/ドメイン/issuer のいずれかがおかしい可能性が高いです。
3. 開発者ツールでリダイレクトチェーンを追う
ブラウザの開発者ツール(Network タブ)を開き、ログイン操作を行った際のリクエストの流れを確認します。
/.auth/login/ciamから CIAM のエンドポイントへのリダイレクト- CIAM から
/.auth/login/ciam/callbackに戻ってくる 302 - その後、
/や/.auth/meへのアクセスで 200 が返っているか
などを見て、どこで 401 や 302 が繰り返されているのかを特定します。常に /.auth/login/ciam と / の 302 が繰り返されている場合は、クッキーが受け取れていないか、issuer mismatch などで内部的に破棄されている可能性があります。
4. SWA のログを確認する
Azure Static Web Apps のリソースから、ログストリーミングや Application Insights を使って、
issuer mismatchinvalid audience- クライアントシークレット未設定関連のエラー
などが出ていないか確認しましょう。構成ファイル上でどこを間違えたかのヒントになることが多いです。
よくある質問と実務的な Tips
Q1. スコープ openid profile email を必ず指定する必要はありますか?
いいえ、必須ではありません。これらは OIDC 標準スコープであり、Azure Static Web Apps 側が既定で要求するため、指定しなくても問題なくクレームが取得できます。
一方で、アプリ側で独自にスコープチェックを実装している場合(例:email クレーム必須など)は、明示的に login.scopes に追加しておくとわかりやすくなります。
Q2. Implicit フローやハイブリッドフローの設定は必要ですか?
Azure Static Web Apps のマネージド認証は、基本的に 認可コードフロー(サーバーサイドでコードを受け取り、バックエンドでトークン交換)で動作します。CIAM 側のアプリは 「Web」アプリとして登録し、特別な SPA 設定をしないのがポイントです。
Q3. 本番/ステージング環境ではどう構成すべき?
実務上は、以下のような構成にすると管理しやすくなります。
- CIAM テナント:1つにまとめる(運用コスト削減のため)。
- アプリ登録:
- 本番用 Static Web Apps(カスタムドメイン)
- ステージング用 Static Web Apps(自動生成ドメイン)
- SWA 側:
- 本番・ステージングともに同じ
staticwebapp.config.jsonを使用しつつ、 - アプリ設定(
AZURE_CLIENT_ID,AZURE_CLIENT_SECRET)だけ環境ごとに切り替える。
- 本番・ステージングともに同じ
こうしておくと、config ファイルを環境ごとに複製せずにすむため、認証まわりのドリフト(差異)が減り、トラブルシューティングもしやすくなります。
まとめ:これで CIAM への移行後の認証ループは解消できる
最後に、本記事で押さえたポイントを整理します。
- CIAM テナント (ciamlogin.com) は SWA の組み込み
azureActiveDirectoryではサポートされないため、customOpenIdConnectProvidersとして構成する。 - プロバイダー名(例:
ciam)は、ログイン URL / コールバック URL の一部になる。- ログイン:
/.auth/login/ciam - コールバック:
/.auth/login/ciam/callback
- ログイン:
/.auth/*は必ず anonymous で開放し、それ以外を authenticated にする。clientSecretSettingNameは、まずはregistration直下にシンプルに書く構成から始め、Key Vault 等を使う場合は公式ドキュメントのclientCredentialパターンに慎重に切り替える。- カスタムドメインを使う場合は、staticwebapps.net とカスタムドメインの両方のコールバック URIを CIAM 側に登録する。
- 動作確認では
/.auth/login/ciam?post_login_redirect_uri=//.auth/me
これらを一つ一つ確認していけば、MFA 後に延々とサインイン画面へ戻される「認証ループ」は解消され、Microsoft Entra External ID (CIAM) を利用した Azure Static Web Apps の認証を安定して稼働させられるはずです。

コメント