错误信息
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/"
两个带引号的 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 强制执行这一点,因为每个 ID 令牌的 `iss` 都要与 `issuer` 值比较。第一个带引号的 URL 是你的,第二个是提供商的。
原因
末尾斜杠不同
常见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 获取发现文档,同时按公共颁发者校验令牌。只在你能控制的内外网分离(split-horizon)部署中使用它;这个名称就是在提醒其中的取舍。
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")