概要
Azure Static Web Apps(SWA)で自社テナント(Entra ID)アカウントだけ
ログイン可能にしたい人向けに、カスタム認証+Role Assignments APIの構成・手順とハマりやすいポイントをまとめました。
公式ドキュメントにあまり乗っていない注意ポイント満載です。
(めっちゃ辛かった。。)
前提条件
- Azure Static Web Apps(SWA)がStandardプラン(※Freeプランではカスタム認証は使えません)
- SWAでアプリがすでに存在している
- Azure Entra ID(旧Azure AD)管理権限がある(もしくは頼むことができる)
- SWAでカスタム認証を使うためのAzure Functions(API)を配置できる
僕の実体験:ここでハマった!勘違いポイントと注意
「簡易認証」でも社員だけログインできると思い込んでいた
- 僕は最初、 「簡易認証のEntra ID設定で社員だけ認証できるはず」 だと信じていました。
- でも実際にはSWAポータルで「Entra ID」を追加する画面が見つからず、ずっと簡易認証のまま探して無駄に時間を消費…。
その結果、外部テナントやMicrosoftアカウントでもログインできてしまい、「あれ、なぜ?」と焦りました。 - 実は「カスタム認証」モードじゃないとIDやシークレットの入力欄が出てきません!
- 「自社テナント限定」にしたいならカスタム認証(Standardプラン)が必要です!
Role Assignments APIって要るの?なぜ追加できないの?
-
カスタム認証に切り替えてEntra IDの追加ボタンを押すと、「Role assignments API path」が必須。
-
最初は「認証だけでいけるのでは?」と思ってたけど、このAPIのパス(例:
/api/getRolesForUsers
)が絶対必要で、これが空だと「追加」ボタンが押せない仕組みだった! -
何をすればいいか分からず混乱したけど、実際はAzure Functions等で全員に
/api/getRolesForUsers
だけ返すAPIを作ればOK。 -
例:
// api/roles/index.js module.exports = async function (context, req) { context.res = { body: { roles: ["authenticated"] } }; };
-
これをSWAにデプロイしてRole assignments API path に
/api/getRolesForUsers
** を指定するだけ! -
「認証後、誰にどんなロールを割り当てるか」をSWAがAPIで毎回聞きにくる仕様なので、このAPIのURL指定が必須だった、という話です。
Azureポータルでの登録は環境変数の定義に過ぎない!?
-
staticwebapp.config.jsonに環境変数を参照することを定義しないといけないのにかなり躓きました。わかりにくい・・・。
-
また、Azureポータルでの登録は、「メイン環境」での定義に過ぎないため、別環境を定義している場合はAzureポータルで別途環境変数の定義が必要でした。
-
またアクセスできるロール定義
"allowedRoles": ["authenticated"]
を忘れると、認証しても全員アクセスできてしまうので注意!
1. Entra IDでアプリ登録(シングルテナント)
1-1. Azureポータルから「アプリの登録」
-
https://portal.azure.com にアクセス
-
「Microsoft Entra ID」→「アプリの登録」→「新規登録」
- 名前:用途がわかる名称
- サポートされているアカウントの種類:
この組織ディレクトリ内のアカウントのみに対応(シングルテナント) - リダイレクトURI:
-
Web
https://<YOUR-SWA-NAME>.azurestaticapps.net/.auth/login/aad/callback
-
ステージング/テスト/PR環境もある場合は、全ての環境分を後から追加で登録(これを忘れると認証エラーになるので注意!)
-
SPAにするとなぜか動かなかったです。以下参照
https://qiita.com/ayukiyama/items/55ed7c5d2af8a2648045
-
1-2. 追加設定 【暗黙的な許可およびハイブリッド フロー】
「認証」から 暗黙的な許可およびハイブリッド フローの項目で、
1-3. アプリ登録後の情報を控える
- アプリケーション(クライアント)ID
- ディレクトリ(テナント)ID
- 「証明書とシークレット」→「新しいクライアントシークレット」を作成し、控える
※クライアントシークレットでは「値」が必要で最初しか見れないです。(見れなくなったらもう一度作成すればいいです。)
2. SWAの「カスタム認証」モードを有効化
- AzureポータルでStatic Web Appsのリソースを開く
- 「認証」→「認証モード」を「カスタム」に変更
- 「認証プロバイダー」タブで「追加」→「Entra ID」
- アプリケーションID
- テナントID
- クライアントシークレット
-
Role assignments API path:
/api/getRolesForUsers
(後述のAPIエンドポイント。空だと追加できない)
- 保存
3. Role Assignments API(Azure Functions)の実装
3-1. 最小サンプル(JavaScript / Python)
僕はPythonでやりましたが、どちらでもOK。
JavaScript (api/roles/index.js)
module.exports = async function (context, req) {
context.res = {
body: { roles: ["authenticated"] }
};
};
Python (api/roles/init.py)
import azure.functions as func
import json
def main(req: func.HttpRequest) -> func.HttpResponse:
return func.HttpResponse(
json.dumps({"roles": ["authenticated"]}),
mimetype="application/json"
)
3-2. APIエンドポイントの設置
- プロジェクト内の
/api/getRolesForUsers
として設置し、SWAでデプロイ - SWAポータルのRole assignments API pathで
/api/getRolesForUsers
を指定 - ここについてはAzureFunctionの知識も必要になるので、一旦省略します。
4. staticwebapp.config.json の設定
{
"auth": {
"identityProviders": {
"azureActiveDirectory": {
"registration": {
"openIdIssuer": "https://login.microsoftonline.com/<テナント_ID>/v2.0",
"clientIdSettingName": "AZURE_CLIENT_ID",
"clientSecretSettingName": "AZURE_CLIENT_SECRET_APP_SETTING_NAME"
}
}
}
},
"routes": [
{
"route": "/.auth/login/twitter",
"statusCode": 404
},
{
"route": "/.auth/login/github",
"statusCode": 404
},
{
"route": "/.auth/*",
"allowedRoles": [
"anonymous",
"authenticated"
]
},
{
"route": "/*",
"allowedRoles": [
"authenticated"
]
}
]
}
-
プロジェクトの
public
フォルダ(またはルート)に配置 -
これで認証済みユーザー(社員)だけがアクセス可能に
-
特に以下の
AZURE_CLIENT_ID
とAZURE_CLIENT_SECRET_APP_SETTING_NAME
はさきほどAzureポータルで登録した環境変数なので、そのままコピペしましょう。{ "auth": { "identityProviders": { "azureActiveDirectory": { "registration": { "openIdIssuer": "https://login.microsoftonline.com/<テナント_ID>/v2.0", "clientIdSettingName": "AZURE_CLIENT_ID", "clientSecretSettingName": "AZURE_CLIENT_SECRET_APP_SETTING_NAME" } } } } }
5. フロー全体まとめ
- ユーザーがSWAにアクセス
- Entra ID認証画面にリダイレクト
- 認証後、リダイレクトURI(SWA)に戻る
- SWAがRole Assignments API(
/api/getRolesForUsers
)を呼び出しロール判定 - allowedRolesで認可
6. それでも「全アカウントで入れてしまう」ときのチェックリスト
僕もここで丸一日ハマりました。原因はたいてい設定漏れか勘違いです。
-
Entra IDアプリ登録が本当に「シングルテナント」か?
- Azureポータル → アプリ登録 → 概要 → サポートされているアカウントの種類 を確認。
この組織ディレクトリ内のアカウントのみ (シングル テナント)
になっていないと外部が入れます。
- Azureポータル → アプリ登録 → 概要 → サポートされているアカウントの種類 を確認。
-
SWAで有効にしているプロバイダーは「Azure Active Directory」だけか?
- 認証 → ID プロバイダー 画面で 「Microsoft」(MSA個人アカウント) が有効になっていないか確認。
- GitHub など他のプロバイダーも無効化。
- Azure AD と Microsoft はアイコンが似ていて間違えやすいポイント!
-
staticwebapp.config.json は正しくデプロイされたか?
- ビルド出力フォルダにファイルが含まれているか。
- Azureポータルの「App files」で
staticwebapp.config.json
が見えるかを確認。
-
navigationFallback が先にマッチしていないか?
-
例:
{ "navigationFallback": { "rewrite": "/index.html" }, "routes": [ { "route": "/*", "allowedRoles": ["authenticated"] } ] }
これだと navigationFallback が先にヒットして認可がスキップされます。
→ routes を上に書く / strict オプションを付けるなど順序に注意!
-
-
トークンの
tid
クレームを確認する- ブラウザ F12 → Network で
/.auth/me
を見る。 -
userId
やclaims.tid
が自社テナント GUID になっているかチェック。
- ブラウザ F12 → Network で
-
Role Assignments API が正しく 200 を返しているか?
- SWAのログ (診断ログ) や Function のログで
/api/getRolesForUsers
が叩かれているか確認。
- SWAのログ (診断ログ) や Function のログで
上記を全部クリアすれば、社員以外が入れるパターンはほぼ潰せます!
7. 注意・補足
- Entra IDアプリ登録は必ず「シングルテナント」!(外部テナント排除のため)
- Role Assignments APIで細かいロール割り当ても可能(例:特定ユーザーをadmin等)
-
allowedRoles
でさらに厳密なルートごとの制御もできる - リダイレクトURIは本番・ステージングなどすべての環境分を忘れずに登録!
- 登録していないリダイレクトURIでは認証時にエラー(AADSTS50011等)になる
8. まとめ
- カスタム認証+Role Assignments APIで「社員のみログイン」を実現
- 自社Entra ID(シングルテナント)のみを許可
- 最小構成ならAPIは“全員にauthenticatedを返す”だけでもOK
- 「簡易認証でイケる」と思って進めてハマる人が多いので、カスタム認証前提で設計するのが安心!
- ハマりどころは「Role assignments API pathが空だと追加できない」「リダイレクトURIの追加漏れ(SPAはうまくいかない)」「configの書き忘れ」など