Error message
Jwks doesn't have key to match kid or alg from Jwt
Also printed as
- Jwt verification fails
- Jwks remote fetch is failed
Response body of the 401; the `WWW-Authenticate` header carries `error="invalid_token"`. A provider whose `remote_jwks` cannot be fetched answers "Jwks remote fetch is failed".
Envoy / Istio — envoy.filters.http.jwt_authn (401 response body; Istio RequestAuthentication)
What it means
Envoy's `jwt_authn` filter (also used by Istio's `RequestAuthentication`) looked in the provider's JWKS for a key with the token's `kid` and a type that fits its `alg`, and found none, so it answered 401 with this text as the body. The signature was never checked. If a matching key exists but the signature does not verify, the body is "Jwt verification fails" instead.
Why it happens
The issuer rotated keys and Envoy's cache is older
common`remote_jwks` is cached for `cache_duration` (5 minutes by default). Tokens signed with a key published after the last fetch fail until the cache refreshes.
An inline or local JWKS copy
common`local_jwks` (or Istio's inline `jwks:`) is a snapshot. It never learns about new keys; every rotation breaks authentication until the configuration is updated.
The key with this kid has another type
occasionalThe JWKS has the `kid`, but as an RSA key while the token is ES256 (or the JWK's `alg` disagrees). Envoy requires both to match.
The token belongs to another issuer
occasionalA provider without a narrow `issuer` match, or a request carrying a token from a different identity provider, is checked against the wrong key set.
How to fix it
- 1.
Fetch the JWKS from the issuer
Use `remote_jwks` with a sensible `cache_duration` and asynchronous fetching, so keys are present before tokens use them.
yaml providers: issuer_example: issuer: https://issuer.example.com audiences: ["api://orders"] remote_jwks: http_uri: uri: https://issuer.example.com/.well-known/jwks.json cluster: issuer_jwks # a cluster with TLS to the issuer timeout: 5s cache_duration: 600s async_fetch: { fast_listener: false } # prefetch, and refetch in the background - 2.
In Istio, point to jwksUri
Istiod fetches and pushes the keys; an inline `jwks` value must be updated by hand on every rotation.
yaml apiVersion: security.istio.io/v1 kind: RequestAuthentication metadata: name: orders-jwt spec: selector: matchLabels: { app: orders } jwtRules: - issuer: https://issuer.example.com jwksUri: https://issuer.example.com/.well-known/jwks.json # not an inline "jwks:" copy