Azure ADでlocalhostサブドメインをリダイレクトURIに設定できない理由とHTTPSローカル開発環境構築ガイド

Azure AD(Microsoft Entra ID)でアプリ認証を実装していると、「本番はうまくいくのにローカル開発だけリダイレクトURIでハマる」という相談が非常に多いです。特に app.localhost のような localhost サブドメインを使いたいケースでは、なぜか Azure AD に登録できず、AADSTS500117 エラーで足止めされがちです。この記事では、その理由と実運用で使えるワークアラウンド、そして「ローカルも HTTPS」に寄せるための具体的な構成例を解説します。

目次

Azure AD / Microsoft Entra ID とリダイレクトURIの基本

まず前提として、Azure AD(現 Microsoft Entra ID)のアプリ登録では、OAuth 2.0 / OpenID Connect の「リダイレクトURI(Reply URL)」を厳密にチェックします。

  • スキーム(https:// / http://
  • ホスト名(例: app.ourdomain.com
  • ポート番号(例: :3000
  • パス(例: /auth/callback

これらが事前に登録したものと完全一致しないと、Azure AD はセキュリティの観点からリダイレクトを拒否し、代表的には次のようなエラーを返します。

AADSTS500117: The reply uri specified in the request isn't using a secure scheme.

本番環境では https://app.ourdomain.comhttps://clientxyz.ourdomain.com のような HTTPS のサブドメインを問題なく登録できますが、ローカル開発になると事情が変わります。

ローカル開発でやりたいこと:localhost サブドメインの利用

モダンなSaaSやマルチテナントアプリでは、テナントごとにサブドメインを変える構成が一般的です。

  • 本番例
    • https://app.ourdomain.com
    • https://clientxyz.ourdomain.com
  • 開発環境で模倣したい構成の例
    • http://app.localhost:3000
    • http://clientxyz.localhost:3000

このように、ローカルでも *.localhost を使ってサブドメイン構成を完全に再現したい、というニーズは非常に強いです。テナント判別ロジック、ルーティング、Cookie のスコープなど、本番と同じドメイン設計でテストできるのが理想だからです。

しかし、ここで Azure AD の仕様にぶつかります。

Azure AD が許可する HTTP リダイレクトURIの範囲

Azure AD が HTTP(暗号化されていない通信)を許可するのは、例外的に http://localhost 系のみです。具体的な挙動を表にまとめると次のようになります。

リダイレクトURI登録可否備考
http://localhost許可ポート無し
http://localhost:3000許可ポート指定付きでもOK
http://127.0.0.1:3000不可IP指定は HTTP では拒否される
http://app.localhost:3000不可AADSTS500117 で弾かれる
http://clientxyz.localhost:3000不可同上
https://app.localhost:3000許可HTTPS ならサブドメインもOK

つまり、HTTP を使えるのは ホスト名がちょうど localhost の場合のみであり、サブドメインが付くと通常の外部ドメインと同じ扱いになります。そのため http://app.localhost:3000 は、「安全ではない HTTP の外部リダイレクトURI」と見なされ、AADSTS500117 で拒否されるわけです。

なぜ HTTP の localhost サブドメインが禁止されているのか

Azure AD が http://localhost だけを特別扱いする背景には、次のようなセキュリティ上の理由があります。

  • ネイティブアプリ向けの「例外」として設計されている
    • モバイル / デスクトップアプリからブラウザを開き、最終的にローカルのループバックサーバーに戻すパターンを許容するため。
  • HTTP でのリダイレクトは原則禁止
    • ネットワーク上でトークンが盗聴されるリスクがあるため、実運用では HTTPS が必須。
  • ホスト名を厳密に制限することでフィッシングを防止
    • 例えば http://login.microsoftonline.com.evil.example.com のような紛らわしいドメインを防ぐ思想と同じ。
    • *.localhost を広く HTTP 許可すると、誤設定や意図しないホスト名が混入した場合の影響が読みにくくなる。

結果として、「HTTP を許すのは本当に最小限の http://localhost のみ」という仕様になっています。サブドメインがついた瞬間に、「それはもう普通の外部ドメインなので HTTPS で来てください」という扱いになるイメージです。

RFC 6761 と localhost サブドメインの話

DNS に関する RFC 6761 では、localhost. ドメインは特別な名前として定義されており、そのサブドメインもループバックとして扱うことが推奨されています。つまり理屈の上では、次のドメインも「ローカルループバック扱い」にしてよさそうに見えます。

  • app.localhost
  • clientxyz.localhost

しかし Azure AD の実装上は、RFC の「名前解決上の推奨」と、「ID プロバイダとしてどこまで例外を許すか」は別問題として扱われています。

  • 名前解決(DNS / ブラウザ)レベルでは、*.localhost を 127.0.0.1 に解決するのは妥当。
  • OAuth / OIDC のセキュリティポリシーとしては、リダイレクトURIを許可する範囲は極力絞るべき。

このギャップが、開発者からすると「RFC 的には OK なはずなのに、Azure AD 側の制限で HTTP が使えない」というモヤモヤにつながっているわけです。

現時点の仕様として押さえておくポイント

この記事では、次のような仕様で動作している前提で解説します。

  • HTTP を許可するのは http://localhost(ポート指定可)のみ
  • http://app.localhost など localhost サブドメインは HTTP では不可
  • サブドメインや任意のホスト名を使いたい場合は、HTTPS が必須
  • この制限はセキュリティ要件に基づくもので、緩和のアナウンスは(少なくとも一般公開情報としては)確認されていない

そのため、開発者として現実的に取れる方針は次のどれかになります。

  • ローカルでも HTTPS を立てて Azure AD の仕様に合わせる
  • テスト用の独自ドメインを取得し、そこを HTTPS でローカルに向ける
  • ngrok や devtunnels などのパブリックトンネルで HTTPS エンドポイントを用意する
  • 要件によっては、開発中だけ GitHub / Google 等の別 IdP を使う

実運用で使えるワークアラウンドの比較

代表的な回避策を、メリット・デメリットとともに一覧表にしました。

方法概要メリットデメリット
ローカルで HTTPS を立てる自己署名 or 開発用 CA(mkcert 等)で証明書を発行し、https://app.localhost:3000 に対応させるAzure AD の仕様に完全準拠 本番とほぼ同じ構成でテスト可能証明書の作成・インポートが面倒 全開発マシンで信頼済みルートを登録する必要
テスト用の独自ドメインを取得例: dev.myapp.test を 127.0.0.1 に向け、HTTPS 化して利用URI をそのままクラウドのステージング環境にも流用しやすい ドメイン戦略を本番と近づけられるドメイン購入や DNS 設定が必要 CI/CD 用の別テスト環境とサブドメインが衝突する可能性
パブリックトンネル(ngrok / devtunnels)を利用ローカルの https://localhost:3000 をインターネット経由の HTTPS URL に公開証明書を自前で用意しなくてもよい モバイル実機や外部メンバーからの動作確認が簡単外部経由のため遅延や通信コストが増える 無料枠の制限・ URL が変わりやすいなどの運用負荷
他の OAuth プロバイダーで開発GitHub / Google 等、http://app.localhost を許可する IdP を利用ローカル開発が非常に手軽 既存のサンプル・ライブラリが豊富Azure AD 固有機能(ロール、条件付きアクセス等)は試せない 本番切り替え時に認証コードの差分が増えるリスク

この中で、長期的に最もおすすめなのは「ローカルでも HTTPS を立てる」パターンです。少々手間でも、一度仕組みさえ作ってしまえば、以降のプロジェクトでも再利用できます。

ローカルで HTTPS を立てる具体的な手順例

ここでは代表的なツールである mkcert を例に、https://app.localhost:3000 を立てる流れをイメージできるように整理します。

mkcert のざっくり手順

  1. 各開発マシンに mkcert をインストールする。
  2. 開発マシンにローカル CA(開発用ルート証明書)をインストールする。
  3. app.localhost 向けのサーバー証明書を発行する。
  4. フロントエンド開発サーバー(例: Vite / webpack-dev-server / ASP.NET Core)で、その証明書を読み込むよう設定する。

コマンド例イメージ(実行環境に合わせて調整してください)。

mkcert -install
mkcert app.localhost

これで app.localhost.pemapp.localhost-key.pem のようなファイルが生成されます。あとは開発サーバーに設定するだけです。

フロントエンド(例: Vite)の設定例イメージ

// vite.config.ts(イメージ)
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import fs from 'fs';

export default defineConfig({
  plugins: [react()],
  server: {
    https: {
      key: fs.readFileSync('./cert/app.localhost-key.pem'),
      cert: fs.readFileSync('./cert/app.localhost.pem'),
    },
    host: 'app.localhost',
    port: 3000,
  },
});

ブラウザ側に mkcert のルート証明書がインポートされていれば、https://app.localhost:3000 で警告なしにアクセスできるようになります。この URL をそのまま Azure AD のリダイレクトURIとして登録すれば、http://app.localhost を使っていた頃とほぼ同じ感覚で開発できます。

テスト用ドメインを取得してローカルに向けるパターン

より本番に近い構成を目指す場合、テスト専用ドメインを取得するのも有力です。

  • 例: dev.myapp.example を本番と別途用意
  • ローカル環境では hosts ファイルや DNS で 127.0.0.1 に向ける
  • ステージング環境では実際のテスト用サーバーに向ける

このアプローチでは、ローカルでもステージングでも https://app.dev.myapp.example のような同一URIで動作させやすくなります。ただし以下の点に注意が必要です。

  • ドメイン名の管理・更新コスト(更新忘れによるトラブルなど)
  • CI / E2E テストで使うサブドメインとの設計調整
  • 証明書をどこまで自動化できるか(Let’s Encrypt / ACME クライアント等)

チームやサービス規模が大きく、ステージング環境も充実させたいケースでは、ローカル専用の *.localhost だけで完結させるよりも、長期的にメリットが出やすい構成と言えるでしょう。

パブリックトンネル(ngrok / devtunnels)の活用

「とりあえず動作確認したい」「モバイル実機から Azure AD 認証を試したい」というときには、パブリックトンネルが手早い選択肢になります。

  • ngrok: ローカルポートを外部の https://xxxx.ngrok.io に公開
  • Dev Tunnels(Visual Studio / VS Code 統合): Microsoft 製のトンネル機能

これらを使えば、ローカルの HTTP / HTTPS サーバーを、Azure AD からアクセス可能な HTTPS URL に変換できます。この URL をリダイレクトURIとして登録すれば、

  • 証明書の生成・インポート
  • hosts や DNS の設定

などの手間をかけずに、即座に Azure AD 認証を試せます。

一方で、以下の点には注意してください。

  • インターネット経由になるため、ローカル専用より遅延や不安定さが増える
  • 無料プランだと URL が都度変わったり、同時接続数に制限がある
  • 機密データを扱う場合は、そもそも外部トンネルを使うべきかを慎重に検討する必要がある

そのため、一時的な検証やデモ用途として割り切って使い、本格的な開発フェーズでは「ローカルで HTTPS」路線に寄せていく、という使い分けが現実的です。

他 IdP での開発と Azure AD 本番の二段構え

もう一つの考え方として、

  • ローカル開発中は GitHub / Google などの IdP で気軽に開発
  • ステージング以降は Azure AD(Entra ID)に切り替えて最終確認

という二段構えもあります。特に

  • シンプルな SPA + API の構成
  • Azure AD 依存機能(グループ、ロール、条件付きアクセスなど)が薄い

といったプロジェクトでは、「とにかく開発効率優先」でこのような構成にするチームも存在します。

ただし、最終的に Azure AD 本番に乗せる以上、

  • トークン形式(スコープ、クレーム)の違い
  • ログイン画面の挙動や多要素認証(MFA)の有無

など、本番とのギャップがどうしても生じます。要件が Azure AD に強く依存する場合は、この方法はあくまで「参考程度」にとどめるのがおすすめです。

Azure AD ポータルでの設定例

実際に Azure ポータルで設定するときの流れも整理しておきます。

SPA(シングルページアプリ)の例

  1. Azure ポータル > Microsoft Entra ID > アプリ登録 を開く。
  2. 対象のアプリを開き、「認証」メニューに移動する。
  3. 「プラットフォームの追加」から 「シングルページ アプリケーション」 を選択する。
  4. リダイレクトURIとして、例えば https://app.localhost:3000 を追加する。
  5. 必要に応じて https://clientxyz.localhost:3000 なども追加する。

MSAL.js の設定イメージは次のようになります。

// msalConfig.ts(イメージ)
import { Configuration } from '@azure/msal-browser';

export const msalConfig: Configuration = {
  auth: {
    clientId: '<アプリケーション (クライアント) ID>',
    authority: 'https://login.microsoftonline.com/<テナントID>',
    redirectUri: 'https://app.localhost:3000',
    postLogoutRedirectUri: 'https://app.localhost:3000',
  },
};

ここで redirectUri が HTTP(http://app.localhost:3000)になっていると、AADSTS500117 が発生します。必ず HTTPS に揃えるようにしてください。

AADSTS500117 エラーが出たときのチェックリスト

AADSTS500117: The reply uri specified in the request isn't using a secure scheme. が出た場合、次のポイントを順に確認すると原因を特定しやすくなります。

  • HTTP になっていないか
    • http://localhost:3000 以外の HTTP URI はすべて NG。
    • http://app.localhost:3000http://127.0.0.1:3000 は使えない。
  • ポート番号が一致しているか
    • 実際のリクエストが https://app.localhost:3001 なのに、ポータルには https://app.localhost:3000 しか登録していない等。
  • 余計なパスやクエリが入っていないか
    • ポータル側に https://app.localhost:3000 を登録したのに、リクエストでは https://app.localhost:3000/callback になっている、など。
  • MSAL 等のライブラリ設定が複数箇所で上書きされていないか
    • 環境変数や設定ファイルをまたぐうちに、redirectUri の値が意図せず HTTP に書き換わっているケースもあります。

ログ出力やブラウザのネットワークタブで、実際に投げられている redirect_uri パラメータの値を確認し、ポータルに登録したものと 1 文字も違いがないかチェックするのがトラブルシューティングの近道です。

今後の見通しと仕様変更への備え

コミュニティでは以前から、

  • *.localhost も RFC 6761 に従ってループバック扱いにしてほしい
  • 開発用途に限って、HTTP の localhost サブドメインを許可してほしい

といった要望が継続的に上がっています。とはいえ、ID プロバイダーにとってリダイレクトURIの制限はセキュリティに直結するため、慎重な判断が必要です。

実務としては、次のようなスタンスを取るのが安全です。

  • 「ローカルでも HTTPS」が今後も推奨され続ける前提で設計する
  • 開発テンプレートやスキャフォールドに、mkcert 等を組み込んでおく
  • Azure AD や OAuth の仕様変更があっても、自分たちのコード側の変更を最小限に抑えられるようにする

もし将来、http://app.localhost のような形が正式に許可されるような仕様変更があれば、それはそれで選択肢として歓迎できますが、それを前提に設計を引き延ばすのではなく、今ある仕様の中で安定した開発基盤を作っておくことが重要です。

まとめ:localhost サブドメイン問題をどう捉えるか

最後に、この記事の要点を整理します。

  • Azure AD(Microsoft Entra ID)は、HTTP のリダイレクトURIとして http://localhost だけを許可している。
  • http://app.localhosthttp://clientxyz.localhost といった localhost サブドメインは HTTP では使用できないため、AADSTS500117 エラーになる。
  • サブドメインを使いたい場合は HTTPS が必須であり、ローカルでも証明書を用意して https://app.localhost:3000 のように構成するのが王道。
  • ワークアラウンドとしては、
    • ローカルで HTTPS を立てる(最もおすすめ)
    • テスト用の独自ドメインを取得してローカルに向ける
    • ngrok / devtunnels などで一時的に公開する
    • 場面によっては他 IdP で開発し、Azure AD で最終確認する
    といった選択肢がある。
  • 将来仕様が緩和される可能性はゼロではないものの、「ローカルも HTTPS」を前提とした開発フローを整えておくのが長期的に安全

「localhost サブドメインを HTTP で使えない」という制約は一見不便ですが、視点を変えると「開発環境から本番環境まで一貫して HTTPS ベースで設計できる」というメリットもあります。チームの標準テンプレートやドキュメントとして、ここで紹介した HTTPS セットアップ手順やワークアラウンドをまとめておくと、今後新しいプロジェクトを立ち上げるときの大きな助けになるはずです。

この記事を書いた人

実務の現場で詰まりがちなポイントを地図にするITブログ「IT trip」を運営。Windows/Office(Teams・Excel)からSQL、サーバ運用、ガジェットまで、再現性のある手順と“なぜそうなるか”を丁寧に解説します。読んだらすぐ試せること、そして迷った人の次の一歩が見えることを大切にしています。

コメント

コメントする

目次