siyuan-note/siyuan · error
decode OIDC claims failed: %w
Error message
decode OIDC claims failed: %w
What it means
After verification, Exchange() unmarshals the ID token's claims into a map[string]any via idToken.Claims. This only fails if the verified token's claims cannot be decoded into the target type, which is essentially an internal invariant violation: go-oidc verified the token, but its claim set is not a JSON object.
Source
Thrown at kernel/model/oidc_provider/provider.go:112
return nil, fmt.Errorf("exchange OIDC authorization code failed: %w", err)
}
if p.kind == conf.OIDCProviderGitHub {
return exchangeGitHubClaims(ctx, token)
}
rawIDToken, ok := token.Extra("id_token").(string)
if !ok || rawIDToken == "" {
return nil, errors.New("OIDC response does not contain an ID token")
}
idToken, err := p.verifier.Verify(ctx, rawIDToken)
if err != nil {
return nil, fmt.Errorf("verify OIDC ID token failed: %w", err)
}
if idToken.Nonce != nonce {
return nil, errors.New("OIDC nonce does not match")
}
claims := map[string]any{}
if err = idToken.Claims(&claims); err != nil {
return nil, fmt.Errorf("decode OIDC claims failed: %w", err)
}
return claims, nil
}
func newGitHub(config *conf.OIDC, redirectURL string) *Provider {
scopes := append([]string{}, config.Scopes...)
if len(scopes) == 0 || isDefaultOIDCScopes(scopes) {
scopes = []string{"read:user", "user:email"}
} else {
filtered := scopes[:0]
for _, scope := range scopes {
if scope != oidc.ScopeOpenID && scope != "profile" && scope != "email" {
filtered = append(filtered, scope)
}
}
scopes = filtered
if !contains(scopes, "read:user") {
scopes = append([]string{"read:user"}, scopes...)View on GitHub (pinned to 8641553a1f)
Solutions
- Capture the raw id_token from the token response and inspect its payload; confirm the claims section is a JSON object
- Update or fix the identity provider, which is producing a non-conformant ID token
- Retry the login flow, since a transiently corrupted response will not reproduce
- File the issue with the IdP vendor if the token payload is persistently non-object JSON
Defensive patterns
Strategy: try-catch
Try / catch
claims := map[string]any{}
if err := idToken.Claims(&claims); err != nil {
return nil, fmt.Errorf("identity provider returned non-object claims; report to IdP vendor: %w", err)
} Prevention
- Validate the IdP against a standard OIDC conformance test before production use
- Capture the raw id_token when this occurs to file a vendor bug
- Keep go-oidc updated for improved claim decoding robustness
When it happens
Trigger: Calling Exchange against a provider that returns an ID token whose claims payload is not a JSON object (e.g. top-level array or string), producing a json unmarshal error inside go-oidc's Claims.
Common situations: Extremely rare; seen with non-conformant or experimental identity providers that mint structurally invalid ID tokens, or with a proxy MITM-ing and corrupting the token payload after signature checks are bypassed by an unusual setup.
Related errors
- decode session data failed: %w
- OIDC claim [%s] is not allowed
- This is not a valid .sy.zip archive. If the archive was expo
- invalid capability arguments: %w
- invalid session data
AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11).
Data as JSON: /api/errors/883e080598474c19.
Report an issue: GitHub.