Message d’erreur
unexpected "iss" claim value
jose (JavaScript) — JWTClaimValidationFailed, code ERR_JWT_CLAIM_VALIDATION_FAILED
Ce que cela signifie
Le jeton a été vérifié cryptographiquement, mais son claim `iss` n’est pas égal à l’option `issuer` que vous avez passée à `jwtVerify`. jose compare les chaînes exactement (un tableau d’émetteurs autorisés est aussi accepté) : toute différence – une barre oblique finale, un autre chemin de locataire, un autre environnement – fait échouer le contrôle. C’est l’épinglage de l’émetteur qui empêche d’accepter un jeton issu d’un autre fournisseur d’identité, ou d’un autre locataire du même fournisseur.
Pourquoi cela se produit
Barre oblique finale ou schéma différent
fréquenteLes fournisseurs ne sont pas cohérents entre eux : Auth0 émet `https://tenant.auth0.com/` avec une barre oblique, Keycloak et Entra ID v2.0 (`…/v2.0`) émettent des URL sans barre oblique, tandis que les jetons Entra ID v1.0 portent `https://sts.windows.net/<tenant>/` avec une barre oblique. Pour une comparaison exacte, `https://login.example.com` et `https://login.example.com/` sont des émetteurs différents.
Mauvais locataire, realm ou serveur d’autorisation
fréquenteLes fournisseurs multilocataires intègrent le locataire dans l’émetteur : Entra ID `https://login.microsoftonline.com/<tenant-id>/v2.0`, Keycloak `https://host/realms/<realm>`, Okta `https://<org>.okta.com/oauth2/<server-id>`. Vérifier par rapport au serveur par défaut alors que les jetons proviennent d’un serveur personnalisé (ou confondre les points de terminaison Entra v1.0 et v2.0) produit cette erreur.
Jeton de préproduction sur un vérificateur de production
occasionnelleLes jetons issus d’un locataire de préproduction ou de développement portent l’émetteur de ce locataire. Lorsque la configuration est copiée d’un environnement à l’autre, le vérificateur et la source des jetons finissent par diverger.
Plusieurs émetteurs légitimes, un seul configuré
occasionnelleLes services qui acceptent des jetons de plusieurs fournisseurs d’identité n’en configurent parfois que le premier. La solution est une liste d’autorisation délibérée, avec un jeu de clés par émetteur, et non la suppression de l’option `issuer`.
Comment corriger l’erreur
- 1.
Prendre la chaîne de l’émetteur dans le document de découverte
La valeur `issuer` de `/.well-known/openid-configuration` est, selon la spécification, exactement ce que le fournisseur écrit dans `iss`. Copiez-la octet pour octet dans votre configuration.
bash # The issuer string is defined by the provider's discovery document. curl -s https://login.example.com/.well-known/openid-configuration | jq -r .issuer - 2.
Épingler cette valeur exacte dans jwtVerify
Conservez l’option `issuer` (sans elle, jose ne vérifie pas du tout `iss`) et gardez-la dans une seule constante partagée par l’URL du JWKS et le vérificateur.
js import { createRemoteJWKSet, jwtVerify } from "jose"; const ISSUER = "https://login.example.com/"; // exactly as in "issuer" from discovery const jwks = createRemoteJWKSet(new URL("https://login.example.com/.well-known/jwks.json")); const { payload } = await jwtVerify(token, jwks, { algorithms: ["ES256"], issuer: ISSUER }); - 3.
Accepter plusieurs émetteurs, avec un jeu de clés chacun
Si votre service fait réellement confiance à plusieurs émetteurs, sélectionnez le jeu de clés d’après l’`iss` (non vérifié) du jeton dans une liste d’autorisation explicite, puis vérifiez en épinglant cet émetteur. Ne laissez jamais les clés d’un émetteur vérifier les jetons d’un autre émetteur.
js import { createRemoteJWKSet, decodeJwt, jwtVerify } from "jose"; // Each trusted issuer gets its own key set; an unknown iss is rejected before any key is used. const trusted = new Map([ ["https://login.example.com/", createRemoteJWKSet(new URL("https://login.example.com/.well-known/jwks.json"))], ["https://partner.example.org", createRemoteJWKSet(new URL("https://partner.example.org/jwks"))], ]); const { iss } = decodeJwt(token); const keys = trusted.get(iss); if (!keys) throw new Error("untrusted issuer"); await jwtVerify(token, keys, { algorithms: ["ES256", "RS256"], issuer: iss });