{"record":{"id":"0c4a7ddc1f4f3222","repo":"Tencent/WeKnora","slug":"no-matching-jwks-key-for-id-token","errorCode":null,"errorMessage":"no matching JWKS key for id_token","messagePattern":"no matching JWKS key for id_token","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/application/service/user.go","lineNumber":1894,"sourceCode":"\t\tif k.Kty != \"\" && !strings.EqualFold(k.Kty, \"RSA\") {\n\t\t\tcontinue\n\t\t}\n\t\tif kid != \"\" && k.Kid != kid {\n\t\t\tcontinue\n\t\t}\n\t\tif _, err := k.rsaPublicKey(); err != nil {\n\t\t\tcontinue\n\t\t}\n\t\tusable = append(usable, k)\n\t}\n\tif kid != \"\" {\n\t\tif len(usable) == 0 {\n\t\t\treturn nil, fmt.Errorf(\"no matching JWKS RSA key for kid %q\", kid)\n\t\t}\n\t\treturn usable[0].rsaPublicKey()\n\t}\n\tif len(usable) == 0 {\n\t\treturn nil, errors.New(\"no matching JWKS key for id_token\")\n\t}\n\tif len(usable) > 1 {\n\t\treturn nil, errors.New(\"id_token missing kid and JWKS contains multiple RSA signing keys\")\n\t}\n\treturn usable[0].rsaPublicKey()\n}\n\n// fetchOIDCJWKS loads the provider's JWKS document over the SSRF-safe client.\nfunc (s *userService) fetchOIDCJWKS(ctx context.Context, jwksURI string) (*oidcJWKS, error) {\n\tif err := validateOIDCEndpoint(\"jwks\", jwksURI, true); err != nil {\n\t\treturn nil, err\n\t}\n\treq, err := http.NewRequestWithContext(ctx, http.MethodGet, jwksURI, nil)\n\tif err != nil {\n\t\treturn nil, err\n\t}\n\treq.Header.Set(\"Accept\", \"application/json\")\n","sourceCodeStart":1876,"sourceCodeEnd":1912,"githubUrl":"https://github.com/Tencent/WeKnora/blob/988cbb03305e055d8ebb7d46d9ac6cc0803cd074/internal/application/service/user.go#L1876-L1912","documentation":"During id_token verification, no RSA key in the fetched JWKS matched the token. If the token carried a kid, no key with that kid existed; if it carried no kid, the JWKS had no usable RSA keys at all. Verification cannot proceed without the provider's signing key.","triggerScenarios":"verifyOIDCIDToken selects rsaKeyForKid(kid) (or the kid-less path) and the filtered `usable` slice is empty — token kid not present in JWKS, or JWKS has zero RSA keys when the token has no kid.","commonSituations":"Provider rotated signing keys and the configured jwks_uri points at a stale copy; jwks_uri misconfigured to the wrong provider's JWKS; token signed with a key not yet published; token missing kid while provider publishes multiple keys elsewhere.","solutions":["Confirm cfg.JwksURI matches the provider's advertised jwks_uri from discovery (.well-known/openid-configuration).","Decode the id_token header and check its kid exists in the JWKS document.","Re-fetch/refresh the JWKS — the key may have been rotated recently.","Ensure the provider includes kid in token headers and publishes the corresponding key."],"exampleFix":"// before\nJwksURI: \"https://old-provider.example.com/.well-known/jwks.json\"\n// after\nJwksURI: discovery.Doc.JWKSURI // from the provider's openid-configuration","handlingStrategy":"retry","validationCode":"// decode token header and pre-check kid against cached JWKS\nparts := strings.Split(idToken, \".\")\nhdr := decodeHeader(parts[0])\nif !jwksHasKid(jwks, hdr.Kid) {\n    jwks = refreshJWKS(ctx, cfg.JwksURI) // key rotation?\n}","typeGuard":"func jwksHasKid(j *oidcJWKS, kid string) bool {\n    for _, k := range j.Keys {\n        if k.Kid == kid && k.Kty == \"RSA\" { return true }\n    }\n    return false\n}","tryCatchPattern":"key, err := svc.VerifyOIDCIDToken(ctx, cfg, idToken)\nif err != nil && strings.Contains(err.Error(), \"no matching JWKS\") {\n    // refresh JWKS once, then retry verification\n    if rerr := svc.RefreshJWKS(ctx, cfg.JwksURI); rerr == nil {\n        key, err = svc.VerifyOIDCIDToken(ctx, cfg, idToken)\n    }\n}","preventionTips":["Derive jwks_uri from provider discovery instead of hardcoding it.","Refresh JWKS on kid-miss (standard rotation handling).","Monitor provider key-rotation announcements."],"tags":["jwks","kid","jwt-verification","oidc"],"backgroundTag":"jwks-key-mismatch","analyzedSha":"988cbb03305e055d8ebb7d46d9ac6cc0803cd074","analyzedAt":"2026-09-02T14:41:08.344Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}