Error message
oidc: issuer URL provided to client ("https://accounts.example.com") did not match the issuer URL returned by provider ("https://accounts.example.com/")
Also printed as
- oidc: issuer did not match the issuer returned by provider, expected "https://accounts.example.com" got "https://accounts.example.com/"
The two quoted URLs are your configured issuer and the provider's `issuer`. go-oidc v3.0–v3.16 printed "oidc: issuer did not match the issuer returned by provider, expected \"…\" got \"…\""; the current wording and the `IssuerMismatchError` type arrived in v3.17.0.
coreos/go-oidc (Go) — *oidc.IssuerMismatchError from oidc.NewProvider
What it means
`oidc.NewProvider` fetched the discovery document from the issuer URL you gave it, and the document's `issuer` field is not exactly that URL. OpenID Connect Discovery requires the two to be identical, and go-oidc enforces it because the `issuer` value is what every ID token's `iss` will be compared with. The first quoted URL is yours, the second is the provider's.
Why it happens
Trailing slash difference
commonAuth0 issuers end with `/`; most others do not. `https://tenant.auth0.com` and `https://tenant.auth0.com/` are different strings to the comparison.
Missing or different path segment
commonKeycloak `…/realms/<realm>`, Entra ID `…/<tenant>/v2.0`, Okta `…/oauth2/default`. Pointing at the host without the path, or at the v1 endpoint of Entra ID, returns a document whose issuer differs.
Discovery fetched through an internal address
occasionalInside a cluster the provider is reached as `http://keycloak:8080/...` while it advertises its public URL as `issuer`. The mismatch is real: tokens will carry the public value.
How to fix it
- 1.
Configure the exact issuer string
Copy `issuer` from the discovery document verbatim, including scheme, path and trailing slash.
bash curl -s https://accounts.example.com/.well-known/openid-configuration | jq -r .issuer # use exactly this string in oidc.NewProvider(ctx, issuer) - 2.
Separate discovery URL and issuer deliberately
`oidc.InsecureIssuerURLContext` lets you fetch discovery from one URL while validating tokens against the public issuer. Use it only for split-horizon setups you control; the name is a reminder of the trade-off.
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")