{"record":{"id":"8274ee470b8fdae7","repo":"Tencent/WeKnora","slug":"id-token-missing-sub-claim","errorCode":null,"errorMessage":"id_token missing sub claim","messagePattern":"id_token missing sub claim","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/user.go","lineNumber":1976,"sourceCode":"\t\t\treturn nil, fmt.Errorf(\"unexpected id_token signing method: %v\", token.Header[\"alg\"])\n\t\t}\n\t\tkid, _ := token.Header[\"kid\"].(string)\n\t\treturn jwks.rsaKeyForKid(kid)\n\t}\n\n\tclaims := jwt.MapClaims{}\n\tif _, err := jwt.NewParser(\n\t\tjwt.WithValidMethods([]string{\"RS256\", \"RS384\", \"RS512\"}),\n\t\tjwt.WithExpirationRequired(),\n\t\tjwt.WithLeeway(oidcIDTokenLeeway),\n\t\tjwt.WithIssuer(strings.TrimSpace(cfg.IssuerURL)),\n\t\tjwt.WithAudience(strings.TrimSpace(cfg.ClientID)),\n\t).ParseWithClaims(idToken, claims, keyFunc); err != nil {\n\t\treturn nil, fmt.Errorf(\"id_token verification failed: %w\", err)\n\t}\n\tverified := map[string]interface{}(claims)\n\tif strings.TrimSpace(extractClaimAsString(verified, \"sub\")) == \"\" {\n\t\treturn nil, errors.New(\"id_token missing sub claim\")\n\t}\n\treturn verified, nil\n}\n\nfunc extractClaimAsString(claims map[string]interface{}, key string) string {\n\tkey = strings.TrimSpace(key)\n\tif key == \"\" {\n\t\treturn \"\"\n\t}\n\tvalue, ok := claims[key]\n\tif !ok || value == nil {\n\t\treturn \"\"\n\t}\n\tswitch v := value.(type) {\n\tcase string:\n\t\treturn strings.TrimSpace(v)\n\tdefault:\n\t\treturn strings.TrimSpace(fmt.Sprint(v))","sourceCodeStart":1958,"sourceCodeEnd":1994,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/user.go#L1958-L1994","documentation":"This error is returned after an OIDC id_token has been cryptographically verified (signature, audience) but the claims payload does not contain a non-empty `sub` (subject) claim. The `sub` claim is mandated by the OIDC spec as the stable, unique identifier of the authenticated user, so without it the service cannot map the token to a user record. It signals a spec-non-compliant or misconfigured identity provider.","triggerScenarios":"Calling the OIDC login/callback flow with an id_token that parses and verifies but whose claims map has no `sub` key or an empty/whitespace-only `sub` value (checked via extractClaimAsString).","commonSituations":"Pointing ClientID/OIDC config at an IdP that omits `sub` (some legacy SAML-bridged or custom token issuers); a token endpoint returning a non-OIDC access token instead of an id_token; misconfigured scopes causing a slimmed-down token template.","solutions":["Verify the IdP actually issues OIDC-compliant ID tokens that include `sub`; inspect a decoded token (e.g. jwt.io) to confirm.","Check OIDC provider configuration/scopes so the issued id_token includes the subject claim.","If using a custom token issuer, add the `sub` claim when minting the token.","Confirm the correct token is being passed (id_token, not access_token) to the verification function."],"exampleFix":"// before: custom issuer omits subject\nclaims := map[string]interface{}{\"iss\": \"my-idp\", \"aud\": cfg.ClientID}\n// after: include the mandatory sub claim\nclaims := map[string]interface{}{\"iss\": \"my-idp\", \"aud\": cfg.ClientID, \"sub\": userUUID}","handlingStrategy":"validation","validationCode":"claims, _ := parseUnverified(idToken)\nif strings.TrimSpace(asString(claims[\"sub\"])) == \"\" {\n    return errors.New(\"id_token has no sub claim; check IdP configuration\")\n}","typeGuard":"func hasSub(claims map[string]interface{}) bool {\n    s, ok := claims[\"sub\"].(string)\n    return ok && strings.TrimSpace(s) != \"\"\n}","tryCatchPattern":null,"preventionTips":["Decode a sample id_token from your IdP and confirm the `sub` claim exists.","Keep IdP/OIDC scopes configured so issued ID tokens are spec-compliant.","Pass the id_token (not the access_token) into the verification function."],"tags":["oidc","jwt","authentication","missing-claim"],"backgroundTag":"jwt-missing-sub-claim","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}