エラーメッセージ
oidc: issuer URL provided to client ("https://accounts.example.com") did not match the issuer URL returned by provider ("https://accounts.example.com/")
別の表記
- oidc: issuer did not match the issuer returned by provider, expected "https://accounts.example.com" got "https://accounts.example.com/"
引用符で囲まれた 2 つの URL は、設定した発行者とプロバイダーの `issuer` です。go-oidc v3.0〜v3.16 は「oidc: issuer did not match the issuer returned by provider, expected \"…\" got \"…\"」と出力していました。現在の表記と `IssuerMismatchError` 型は v3.17.0 で導入されました。
coreos/go-oidc (Go) — *oidc.IssuerMismatchError from oidc.NewProvider
このエラーの意味
`oidc.NewProvider` は指定された発行者 URL からディスカバリドキュメントを取得しましたが、ドキュメントの `issuer` フィールドがその URL と完全には一致しません。OpenID Connect Discovery は両者が同一であることを要求しており、go-oidc もそれを強制します。`issuer` の値は、すべての ID トークンの `iss` と比較される値だからです。引用符で囲まれた最初の URL が設定した値、2 つ目がプロバイダーの値です。
発生する理由
末尾のスラッシュの違い
よくあるAuth0 の発行者は `/` で終わりますが、ほかの多くは終わりません。比較の上では、`https://tenant.auth0.com` と `https://tenant.auth0.com/` は別の文字列です。
パスセグメントが欠けているか異なる
よくあるKeycloak は `…/realms/<realm>`、Entra ID は `…/<tenant>/v2.0`、Okta は `…/oauth2/default` です。パスなしのホストや Entra ID の v1 エンドポイントを指定すると、発行者が異なるドキュメントが返されます。
内部アドレス経由でディスカバリを取得している
ときどきクラスター内ではプロバイダーに `http://keycloak:8080/...` でアクセスしますが、プロバイダーは `issuer` として公開 URL を提示しています。この不一致は実際に問題になります。トークンには公開側の値が入るためです。
修正方法
- 1.
発行者の文字列を正確に設定する
スキーム、パス、末尾のスラッシュを含め、ディスカバリドキュメントの `issuer` をそのままコピーしてください。
bash curl -s https://accounts.example.com/.well-known/openid-configuration | jq -r .issuer # use exactly this string in oidc.NewProvider(ctx, issuer) - 2.
ディスカバリの URL と発行者を意図的に分ける
`oidc.InsecureIssuerURLContext` を使うと、ディスカバリはある URL から取得しつつ、トークンは公開の発行者に対して検証できます。自分で管理するスプリットホライズン構成でのみ使ってください。この名前は、そのトレードオフを忘れないためのものです。
go // Only when discovery must be fetched from an internal address (for example inside Kubernetes) // while tokens carry the public issuer. The verifier still checks iss against the public value. ctx = oidc.InsecureIssuerURLContext(ctx, "https://login.example.com/realms/main") provider, err := oidc.NewProvider(ctx, "http://keycloak.auth.svc.cluster.local:8080/realms/main")