{"record":{"id":"bff5e5d9480d689b","repo":"dgraph-io/dgraph","slug":"while-refreshing-jwk-from-the-url","errorCode":null,"errorMessage":"while refreshing JWK from the URL","messagePattern":"while refreshing JWK from the URL","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"graphql/authorization/auth.go","lineNumber":349,"sourceCode":"\t}\n\tjwtToken := md.Get(string(AuthJwtCtxKey))\n\tif len(jwtToken) != 1 {\n\t\treturn \"\"\n\t}\n\treturn jwtToken[0]\n}\n\n// validateThroughJWKUrl validates the JWT token against the given list of JWKUrls.\n// It returns an error only if the token is not validated against even one of the\n// JWKUrl.\nfunc (a *AuthMeta) validateThroughJWKUrl(jwtStr string) (*jwt.Token, error) {\n\tvar err error\n\tvar token *jwt.Token\n\tfor i := range a.JWKUrls {\n\t\tif a.isExpired(i) {\n\t\t\terr = a.refreshJWK(i)\n\t\t\tif err != nil {\n\t\t\t\treturn nil, errors.Wrap(err, \"while refreshing JWK from the URL\")\n\t\t\t}\n\t\t}\n\n\t\ttoken, err = jwt.ParseWithClaims(\n\t\t\tjwtStr,\n\t\t\t&CustomClaims{authMeta: a},\n\t\t\tfunc(token *jwt.Token) (interface{}, error) {\n\t\t\t\tkid := token.Header[\"kid\"]\n\t\t\t\tif kid == nil {\n\t\t\t\t\treturn nil, errors.Errorf(\"kid not present in JWT\")\n\t\t\t\t}\n\n\t\t\t\tsigningKeys := a.jwkSet[i].Key(kid.(string))\n\t\t\t\tif len(signingKeys) == 0 {\n\t\t\t\t\treturn nil, errors.Errorf(\"Invalid kid\")\n\t\t\t\t}\n\t\t\t\treturn signingKeys[0].Key, nil\n\t\t\t},","sourceCodeStart":331,"sourceCodeEnd":367,"githubUrl":"https://github.com/dgraph-io/dgraph/blob/759e242be62c91f8d084da06ad0c8d21256d9c07/graphql/authorization/auth.go#L331-L367","documentation":"This error wraps any failure that occurs while re-fetching a JSON Web Key (JWK) set from one of the configured JWK URLs before JWT validation. The library refreshes the key set whenever the cached copy has expired (isExpired) and wraps the underlying fetch error (HTTP failure, bad URL, invalid JWK response) with this message. It is a wrapper, so the root cause is in the wrapped error.","triggerScenarios":"validateThroughJWKUrl iterates a.JWKUrls; for any index i where a.isExpired(i) is true, a.refreshJWK(i) fails — e.g. the JWKS endpoint returns 5xx, DNS/network failure, malformed JWK JSON, or a bad URL configured in JWKUrls.","commonSituations":"Identity provider (Auth0/Keycloak/Cognito) JWKS endpoint is down or rate-limiting; firewall blocks egress to the JWKS host; JWK URL typo; cached key set TTL elapsed right before an incoming request is validated; IdP rotated keys and the refresh endpoint changed.","solutions":["Inspect the wrapped cause (errors.Cause / %v) to see whether it is network, HTTP status, or JWK parsing — fix that root issue first.","Verify the JWKUrls entries are reachable from this host (curl the URL from the server).","Check the IdP status page / rate limits if the endpoint returns 429/5xx.","If the cache is expiring too often, increase the expiry interval used by isExpired so refreshes are less frequent.","Add retry with backoff around refreshJWK for transient network failures."],"exampleFix":"// before\nif a.isExpired(i) {\n    if err := a.refreshJWK(i); err != nil {\n        return nil, errors.Wrap(err, \"while refreshing JWK from the URL\")\n    }\n}\n// after\nif a.isExpired(i) {\n    if err := retryWithBackoff(3, func() error { return a.refreshJWK(i) }); err != nil {\n        glog.Errorf(\"JWK refresh failed for %s: %v\", a.JWKUrls[i], err)\n        return nil, errors.Wrapf(err, \"while refreshing JWK from %s\", a.JWKUrls[i])\n    }\n}","handlingStrategy":"retry","validationCode":"// before validating tokens\nfor _, u := range auth.JWKUrls {\n    resp, err := http.Get(u)\n    if err != nil || resp.StatusCode != http.StatusOK {\n        return fmt.Errorf(\"JWK URL %s unreachable: %v\", u, err)\n    }\n    resp.Body.Close()\n}","typeGuard":null,"tryCatchPattern":"if claims, err := auth.ExtractCustomClaims(ctx, jwtStr); err != nil {\n    if strings.Contains(err.Error(), \"while refreshing JWK from the URL\") {\n        // fall back to cached keys or return 503\n        return nil, status.Error(codes.Unavailable, \"auth key source unavailable\")\n    }\n    return nil, err\n}","preventionTips":["Monitor JWKS endpoint availability and alert on failures","Add retry with backoff around JWK refreshes","Keep a last-known-good JWK set to serve during refresh outages","Set a sane JWK cache TTL so refreshes are infrequent"],"tags":["jwt","jwk","network","authentication"],"backgroundTag":"jwks-fetch-failed","analyzedSha":"759e242be62c91f8d084da06ad0c8d21256d9c07","analyzedAt":"2026-09-01T14:42:12.034Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}