knadh/listmonk · error

error getting user from OIDC

Error message

error getting user from OIDC

What it means

This error is returned by ExchangeOIDCToken when the verified OIDC ID token's claims cannot be unmarshalled into the internal OIDCclaim struct via idTk.Claims(&claims). It means the token verified cryptographically but its JSON payload does not fit the expected claim shape, so the user identity cannot be extracted. The library discards the underlying cause, so the real reason (unexpected types, missing fields) is hidden.

Source

Thrown at internal/auth/auth.go:260

	}

	verifier, err := o.getVerifier()
	if err != nil {
		return "", OIDCclaim{}, echo.NewHTTPError(http.StatusUnauthorized, fmt.Sprintf("error getting verifier: %v", err))
	}

	idTk, err := verifier.Verify(context.TODO(), rawIDTk)
	if err != nil {
		return "", OIDCclaim{}, echo.NewHTTPError(http.StatusUnauthorized, fmt.Sprintf("error verifying ID token: %v", err))
	}

	if idTk.Nonce != nonce {
		return "", OIDCclaim{}, echo.NewHTTPError(http.StatusUnauthorized, "nonce did not match")
	}

	var claims OIDCclaim
	if err := idTk.Claims(&claims); err != nil {
		return "", OIDCclaim{}, errors.New("error getting user from OIDC")
	}

	// If claims doesn't have the e-mail, attempt to fetch it from the userinfo endpoint.
	if claims.Email == "" {
		provider, err := o.getProvider()
		if err != nil {
			return "", OIDCclaim{}, fmt.Errorf("error getting provider: %v", err)
		}

		userInfo, err := provider.UserInfo(context.TODO(), oauth2.StaticTokenSource(tk))
		if err != nil {
			return "", OIDCclaim{}, errors.New("error fetching user info from OIDC")
		}

		// Parse the UserInfo claims into the claims struct
		if err := userInfo.Claims(&claims); err != nil {
			return "", OIDCclaim{}, errors.New("error parsing user info claims")
		}

View on GitHub (pinned to 670c01717d)

Solutions

  1. Check the raw ID token payload (decode at jwt.io or idToken.Claims into map[string]interface{}) and compare its types against the OIDCclaim struct field types.
  2. Fix the OIDCclaim struct (or add custom json tags / use json.RawMessage for flexible fields) to match what your IdP actually sends.
  3. Wrap the error with %w or log the underlying err before returning so the real mismatch is diagnosable.
  4. Verify the expected OIDC scopes are requested so standard claims (email, name) are present and well-typed.

Example fix

// before
var claims OIDCclaim
if err := idTk.Claims(&claims); err != nil {
	return "", OIDCclaim{}, errors.New("error getting user from OIDC")
}
// after
var claims OIDCclaim
if err := idTk.Claims(&claims); err != nil {
	return "", OIDCclaim{}, fmt.Errorf("error getting user from OIDC: %w", err)
}
Defensive patterns

Strategy: try-catch

Validate before calling

var probe map[string]interface{}
if err := json.Unmarshal(rawIDTokenPayload, &probe); err != nil {
	// token claims are not valid JSON; do not call ExchangeOIDCToken flow
}

Type guard

func hasWellTypedClaims(m map[string]interface{}) bool {
	for _, k := range []string{"email", "name", "sub"} {
		if v, ok := m[k]; ok {
			if _, ok := v.(string); !ok {
				return false
			}
		}
	}
	return true
}

Try / catch

if _, claims, err := auth.ExchangeOIDCToken(code, nonce); err != nil {
	if strings.Contains(err.Error(), "error getting user from OIDC") {
		log.Printf("OIDC claim parse failure: %v", err) // 500, not retryable
	}
	return err
}

Prevention

When it happens

Trigger: The ID token's claims JSON contains fields whose types do not match OIDCclaim (e.g. email as a non-string, numeric claims as floats vs ints) or is malformed, causing the go-oidc Claims() json.Unmarshal into *OIDCclaim to fail after successful token verification and nonce check.

Common situations: An identity provider emits non-standard claim types (e.g. a claim that is an object or number where OIDCclaim expects a string); a provider update changes claim shapes; a misconfigured custom claim mapping produces type mismatches.

Related errors


AI-assisted analysis of knadh/listmonk@670c01717d (2026-09-01). Data as JSON: /api/errors/41b9f24203287769. Report an issue: GitHub.