dgraph-io/dgraph · error

while refreshing JWK from the URL

Error message

while refreshing JWK from the URL

What it means

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.

Source

Thrown at graphql/authorization/auth.go:349

	}
	jwtToken := md.Get(string(AuthJwtCtxKey))
	if len(jwtToken) != 1 {
		return ""
	}
	return jwtToken[0]
}

// validateThroughJWKUrl validates the JWT token against the given list of JWKUrls.
// It returns an error only if the token is not validated against even one of the
// JWKUrl.
func (a *AuthMeta) validateThroughJWKUrl(jwtStr string) (*jwt.Token, error) {
	var err error
	var token *jwt.Token
	for i := range a.JWKUrls {
		if a.isExpired(i) {
			err = a.refreshJWK(i)
			if err != nil {
				return nil, errors.Wrap(err, "while refreshing JWK from the URL")
			}
		}

		token, err = jwt.ParseWithClaims(
			jwtStr,
			&CustomClaims{authMeta: a},
			func(token *jwt.Token) (interface{}, error) {
				kid := token.Header["kid"]
				if kid == nil {
					return nil, errors.Errorf("kid not present in JWT")
				}

				signingKeys := a.jwkSet[i].Key(kid.(string))
				if len(signingKeys) == 0 {
					return nil, errors.Errorf("Invalid kid")
				}
				return signingKeys[0].Key, nil
			},

View on GitHub (pinned to 759e242be6)

Solutions

  1. Inspect the wrapped cause (errors.Cause / %v) to see whether it is network, HTTP status, or JWK parsing — fix that root issue first.
  2. Verify the JWKUrls entries are reachable from this host (curl the URL from the server).
  3. Check the IdP status page / rate limits if the endpoint returns 429/5xx.
  4. If the cache is expiring too often, increase the expiry interval used by isExpired so refreshes are less frequent.
  5. Add retry with backoff around refreshJWK for transient network failures.

Example fix

// before
if a.isExpired(i) {
    if err := a.refreshJWK(i); err != nil {
        return nil, errors.Wrap(err, "while refreshing JWK from the URL")
    }
}
// after
if a.isExpired(i) {
    if err := retryWithBackoff(3, func() error { return a.refreshJWK(i) }); err != nil {
        glog.Errorf("JWK refresh failed for %s: %v", a.JWKUrls[i], err)
        return nil, errors.Wrapf(err, "while refreshing JWK from %s", a.JWKUrls[i])
    }
}
Defensive patterns

Strategy: retry

Validate before calling

// before validating tokens
for _, u := range auth.JWKUrls {
    resp, err := http.Get(u)
    if err != nil || resp.StatusCode != http.StatusOK {
        return fmt.Errorf("JWK URL %s unreachable: %v", u, err)
    }
    resp.Body.Close()
}

Try / catch

if claims, err := auth.ExtractCustomClaims(ctx, jwtStr); err != nil {
    if strings.Contains(err.Error(), "while refreshing JWK from the URL") {
        // fall back to cached keys or return 503
        return nil, status.Error(codes.Unavailable, "auth key source unavailable")
    }
    return nil, err
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of dgraph-io/dgraph@759e242be6 (2026-09-01). Data as JSON: /api/errors/bff5e5d9480d689b. Report an issue: GitHub.