{"record":{"id":"eaabb52a1cb48959","repo":"juanfont/headscale","slug":"decoding-id-token-claims-w","errorCode":null,"errorMessage":"decoding ID token claims: %w","messagePattern":"decoding ID token claims: %w","errorType":"http","errorClass":null,"httpStatus":500,"severity":"error","filePath":"hscontrol/oidc.go","lineNumber":284,"sourceCode":"\t\thttpUserError(writer, NewHTTPError(http.StatusBadRequest, \"nonce not found\", err))\n\t\treturn\n\t}\n\n\tif idToken.Nonce != nonce.Value {\n\t\thttpUserError(writer, NewHTTPError(http.StatusForbidden, \"nonce did not match\", nil))\n\t\treturn\n\t}\n\n\t// The state/nonce cookies have served their CSRF purpose; clear them so a\n\t// single-use pair does not linger in the browser until MaxAge.\n\tclearOIDCCallbackCookie(writer, stateCookieName)\n\tclearOIDCCallbackCookie(writer, nonceCookieName)\n\n\tnodeExpiry := a.determineNodeExpiry(idToken.Expiry)\n\n\tvar claims types.OIDCClaims\n\tif err := idToken.Claims(&claims); err != nil { //nolint:noinlineerr\n\t\thttpUserError(writer, fmt.Errorf(\"decoding ID token claims: %w\", err))\n\t\treturn\n\t}\n\n\t// Fetch user information (email, groups, name, etc) from the userinfo endpoint\n\t// https://openid.net/specs/openid-connect-core-1_0.html#UserInfo\n\tvar userinfo *oidc.UserInfo\n\n\tuserinfo, err = a.oidcProvider.UserInfo(req.Context(), oauth2.StaticTokenSource(oauth2Token))\n\tif err != nil {\n\t\tutil.LogErr(err, \"could not get userinfo; only using claims from id token\")\n\t}\n\n\t// The [oidc.UserInfo] type only decodes some fields (Subject, Profile, Email, EmailVerified).\n\t// We are interested in other fields too (e.g. groups are required for allowedGroups) so we\n\t// decode into our own [types.OIDCUserInfo] type using the underlying claims struct.\n\tvar userinfo2 types.OIDCUserInfo\n\tif userinfo != nil && userinfo.Claims(&userinfo2) == nil && userinfo2.Sub == claims.Sub {\n\t\t// Update the user with the userinfo claims (with id token claims as fallback).","sourceCodeStart":266,"sourceCodeEnd":302,"githubUrl":"https://github.com/juanfont/headscale/blob/565fd254d06c4c7f9a8cad1714a43445c79ba420/hscontrol/oidc.go#L266-L302","documentation":"Error \"decoding ID token claims: %w\" thrown in juanfont/headscale.","triggerScenarios":"Thrown at hscontrol/oidc.go:284 when the library encounters an invalid state.","commonSituations":"The claims inside the OIDC ID token could not be decoded. Verify the identity provider returns a standard JWT ID token with the expected claims.","solutions":["Inspect the wrapped error for the underlying cause and correct the failing condition (decoding ID token claims); retry the operation after fixing the input, configuration, or environment."],"exampleFix":"Inspect the wrapped error for the underlying cause and correct the failing condition (decoding ID token claims); retry the operation after fixing the input, configuration, or environment.","handlingStrategy":null,"validationCode":null,"typeGuard":null,"tryCatchPattern":null,"preventionTips":[],"tags":[],"backgroundTag":null,"analyzedSha":"565fd254d06c4c7f9a8cad1714a43445c79ba420","analyzedAt":"2026-08-15T13:12:30.133Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}