Mensaje de error
Unable to find a signing key that matches: "2026-10"
También se muestra como
- jwt.exceptions.PyJWKClientError: Unable to find a signing key that matches: "2026-10"
- Unable to find a signing key that matches: "None"
El valor entre comillas es el `kid` del token; `"None"` significa que el encabezado no tiene `kid`.
PyJWT (Python) — jwt.exceptions.PyJWKClientError from PyJWKClient.get_signing_key_from_jwt
Qué significa
`PyJWKClient` descargó el conjunto de claves y no encontró ninguna clave de firma cuyo `kid` sea igual al `kid` del encabezado del token (el que aparece entre comillas). PyJWKClient vuelve a descargar el conjunto de claves una vez cuando un `kid` es desconocido, así que la clave realmente no está publicada en esa URL en este momento. `"None"` entre comillas significa que el token no tiene ningún `kid`.
Por qué ocurre
La clave de firma se rotó antes de publicarse
frecuenteSi el emisor firma con una clave nueva antes de añadirla al JWKS (o si una CDN sirve una copia obsoleta del JWKS), los verificadores no pueden encontrarla. Los emisores deberían publicar primero la clave nueva y pasar a usarla cuando hayan caducado las cachés.
El cliente apunta al conjunto de claves de otro emisor
frecuenteLas URL de JWKS específicas de cada tenant (grupos de usuarios de Cognito, tenants de Auth0, realms de Keycloak, tenants de Entra ID) se parecen entre sí. Una URL de otro entorno devuelve claves reales, solo que no las de este token.
El encabezado del token no tiene kid
ocasional`PyJWKClient.get_signing_key_from_jwt` busca la coincidencia estrictamente por `kid`. Los tokens de emisores que lo omiten no pueden resolverse así; en su lugar, verifica explícitamente con la única clave publicada.
La clave existe, pero no es una clave de firma utilizable
ocasionalPyJWKClient solo tiene en cuenta las claves con `use` ausente o igual a `"sig"` que PyJWT pueda cargar; una clave de un tipo no compatible se omite. Si el `kid` aparece en el JSON sin procesar, pero no en `get_signing_keys()`, esta es la razón.
Cómo solucionarlo
- 1.
Comparar el kid del token con las claves cargadas
`get_signing_keys(refresh=True)` muestra exactamente qué claves puede usar PyJWKClient. Si el `kid` del token no está ahí, el problema es el emisor o la URL, no tu código.
python print(jwt.get_unverified_header(token).get("kid")) for key in client.get_signing_keys(refresh=True): print(key.key_id, key.algorithm_name) - 2.
Reutilizar un único PyJWKClient
Crear el cliente en cada solicitud desactiva la caché y hace una petición al emisor en cada llamada. Un cliente de larga duración con caché de claves aun así vuelve a descargar las claves cuando aparece un `kid` nuevo.
python from jwt import PyJWKClient # Module level: one client, cached keys, refetch on an unknown kid. JWKS = PyJWKClient("https://issuer.example.com/.well-known/jwks.json", cache_keys=True, lifespan=600) def verify(token: str) -> dict: signing_key = JWKS.get_signing_key_from_jwt(token) return jwt.decode(token, signing_key.key, algorithms=["ES256"], audience="https://api.example.com")