0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ZITADEL を localhost で試すと OIDC Discovery が失敗する件とその対処

Last updated at Posted at 2025-07-06

Introduction

ZITADEL をローカル環境で動作検証する際、UI にアクセスしたブラウザが /.well-known/openid-configuration にリクエストを送るタイミングで CORS エラーが発生し、OIDC の初期化に失敗することがあります。

結論

ローカルの動作検証なので手抜きして EXTERNAL_DOMAIN に localhost を使っていたのを hosts ファイルで定義した別の FQDN 形式の名前に変更したところ、問題なく動作するようになりました。

発生した事象

  • ZITADEL を --tlsMode server で 10443 ポートにて起動(rootless コンテナ運用のため)
  • ブラウザから https://localhost:10443/ui/console/ にアクセス
  • Web UI の内部処理で https://localhost/.well-known/openid-configuration へリクエストが飛ぶ
  • 実際のポートは 10443 なので、ZITADEL に到達せず無応答(CORS エラーや 404 ではなく)

技術的背景

ZITADEL の UI(JavaScript)は environment.json にある issuer 値を元に .well-known の URL を組み立てています。

{
  "issuer": "https://localhost:10443"
}

この値に基づいて JS 側では次のようなコードで .well-known を参照します:

const wellKnownUrl = issuer + "/.well-known/openid-configuration";

そして実際のコード上では、loadDiscoveryDocument() 関数において、明示的に issuer を指定していない場合はこの issuer 値を使って .well-known の URL を構成し、HTTP リクエストを送信します。

K || (
  (K = this.issuer || "").endsWith("/") || (K += "/"),
  K += ".well-known/openid-configuration"
);
this.http.get(K)

今回の事象では environment.json にも issuer にもポートが含まれているにもかかわらず、実際にブラウザが送信したリクエストではポートが省略されており、https://localhost/.well-known/openid-configuration にアクセスしようとして失敗していました。

なお、curl による environment.json の取得結果にも明確にポートが含まれていたことが確認できています:

$ curl -k https://auth.example.local:10443/ui/console/assets/environment.json | jq .
{
  "api": "https://auth.example.local:10443",
  "issuer": "https://auth.example.local:10443",
  "clientid": "327587995391820388"
}

ポートがどこで消えているかについては、ZITADEL の UI バンドルされた JavaScript の中で issuer の値が URL オブジェクトとして解釈されたり、別の処理を経てポートが省略されている可能性はありますが、今回の検証ではその詳細までは特定に至っていません。

回避策

  • /etc/hosts に次のように追記して:

    127.0.0.1   auth.example.local
    
  • ZITADEL の EXTERNAL_DOMAINauth.example.local に設定

  • ブラウザから https://auth.example.local:10443 でアクセス

これにより、issuer と実際の origin が一致し、.well-known の取得や CORS 判定も正常に通ります。

おわりに

ZITADEL のバグというよりは、localhost の取り扱いが特殊であることに起因する想定外の動作と思われます。

ローカル検証時にも localhost を避けて名前付きホストを使うのが安全です。


補足:CORS とは?

CORS(Cross-Origin Resource Sharing)とは、ブラウザが異なる「オリジン」へのリクエストを制限する仕組みです。

「オリジン」とは、スキーム(http/https)・ホスト名・ポート番号の組み合わせを指し、これらがすべて一致していないと 「異なるオリジン」 とみなされます。

今回のように:

  • 表示中のページが https://localhost:10443 であるのに、
  • JavaScript が https://localhost/.well-known/... にアクセスすると、

ポート番号の不一致によってオリジンが異なると判定され、サーバ側が CORS 許可をしていないとアクセスがブロックされます。

ZITADEL 側が .well-knownAccess-Control-Allow-Origin ヘッダを返していれば問題になりませんが、 一般的には明示的な許可がなければ 異なるオリジン間通信は遮断されます。

さらに補足

この記事は 80% 程度 ChatGPT が書いてくれました。

いつも面倒なのでいろいろ試しても記録を残さないままになっていますが、ChatGPT とやりとりしながらした試行錯誤は「これまとめといて」でわりと使える感じのレポートができる、という点に気付いたのが今回の一番の収穫かも知れません。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?