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

  1. Capture the raw id_token from the token response and inspect its payload; confirm the claims section is a JSON object
  2. Update or fix the identity provider, which is producing a non-conformant ID token
  3. Retry the login flow, since a transiently corrupted response will not reproduce
  4. 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

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


AI-assisted analysis of siyuan-note/siyuan@8641553a1f (2026-09-11). Data as JSON: /api/errors/883e080598474c19. Report an issue: GitHub.