Error message
oidc: malformed jwt: unexpected signature algorithm "ES256"; expected ["RS256"]
Also printed as
- oidc: id token signed with unsupported algorithm, expected ["RS256"] got "ES256"
go-oidc v3.0–v3.5 checked the algorithm after parsing and worded it "oidc: id token signed with unsupported algorithm, expected [\"RS256\"] got \"ES256\""; later releases (checked on v3.10, v3.14, v3.17 and v3.21) reject it while parsing, hence "malformed jwt".
coreos/go-oidc (Go) — IDTokenVerifier.Verify with the default SupportedSigningAlgs
What it means
The ID token is signed with an algorithm that is not in the verifier's `SupportedSigningAlgs`. When that list is empty and the verifier was not created from a discovered provider, go-oidc falls back to RS256 only — the default the OpenID Connect specification mandates — so any ES256, PS256 or EdDSA token is rejected before its signature is checked. go-oidc reports it as a "malformed jwt" because the check happens while parsing the JWS.
Why it happens
Verifier created by hand without algorithms
common`oidc.NewVerifier(issuer, keySet, &oidc.Config{ClientID: …})` with no `SupportedSigningAlgs` accepts RS256 only. Providers that sign with ES256 (and many self-hosted ones do) fail immediately.
The provider changed its signing algorithm
occasionalA verifier with an explicit list breaks when the provider rotates to a key of another type. Discovery-based verifiers pick up the new value from `id_token_signing_alg_values_supported`.
The token is not from this provider
occasionalTokens from another issuer with a different algorithm hit this check before the issuer check.
How to fix it
- 1.
List the provider's algorithm explicitly
Set `SupportedSigningAlgs` to the algorithm(s) the provider uses. Keep the list short; it is an allow-list.
go verifier := oidc.NewVerifier(issuer, keySet, &oidc.Config{ ClientID: clientID, SupportedSigningAlgs: []string{oidc.ES256}, // what the provider actually signs with }) - 2.
Let discovery provide the algorithms
`provider.Verifier` reads the supported algorithms from the provider's metadata, so nothing needs to be kept in sync by hand.
go // provider.Verifier takes the algorithms from id_token_signing_alg_values_supported. provider, err := oidc.NewProvider(ctx, issuer) if err != nil { return err } verifier := provider.Verifier(&oidc.Config{ClientID: clientID})