Lorsqu’un JWT se décode correctement, n’est pas expiré et peut même avoir une signature valide, mais que l’API renvoie invalid audience, audience mismatch ou un 401 générique, je traite aud comme une validation distincte. Une signature valide établit l’intégrité et la relation avec une clé de confiance ; elle ne prouve pas que le token est destiné à cette API.
Si je connais déjà l’audience attendue, je commence par JWT Debugger, puis je remonte jusqu’à la manière dont le client a demandé le token.
Ce que aud signifie réellement
RFC 7519 autorise aud sous forme de chaîne ou de tableau :
{ "aud": "api://orders" }
{ "aud": ["api://orders", "api://reporting"] }
L’API doit retrouver son identifiant attendu dans cette valeur. Je n’ajoute pas de normalisation improvisée — minuscules, suppression de slash ou comparaison partielle — sauf si le profil utilisé la définit explicitement.
Je compare d’abord Expected Audience et Actual Audience
API attend : api://orders-prod
Token aud : api://orders-dev
Résultat : mismatch
Pour un tableau :
function audienceMatches(aud, expected) {
if (typeof aud === "string") return aud === expected;
if (Array.isArray(aud)) return aud.includes(expected);
return false;
}
expected vient de la configuration de confiance du serveur, jamais du token lui-même.
Cause fréquente : token demandé pour la mauvaise resource
L’authentification peut réussir alors que le client demande un token pour une autre API. Je cherche notamment :
- scopes d’une autre resource ;
- identifiant API dev utilisé en prod ;
- configuration copiée d’un autre environnement ;
- gateway et backend qui n’attendent pas le même identifiant ;
- ancien token conservé côté client.
Je corrige l’acquisition OAuth/OIDC, pas la règle de validation.
Cause fréquente : ID Token envoyé à la place de l’Access Token
Un ID Token OpenID Connect est destiné au client qui a lancé l’authentification. Son aud désigne généralement ce client. Une resource API attend plutôt un Access Token destiné à elle.
Si je vois :
{
"iss": "https://login.example.com/",
"aud": "web-client-123",
"sub": "user-42"
}
alors que l’API attend api://orders, je vérifie quelle variable est réellement placée dans Authorization: Bearer.
Cause fréquente : mélange dev/staging/prod
Je lis iss et aud ensemble :
expected iss = https://login.example.com/prod
expected aud = api://orders-prod
actual iss = https://login.example.com/dev
actual aud = api://orders-dev
Si les deux pointent vers dev, une erreur d’environnement ou de tenant est plus probable qu’un problème cryptographique.
Messages d’erreur typiques
invalid audience
audience mismatch
token audience is invalid
audience not allowed
unexpected "aud" claim value
Je ne m’arrête pas au texte : je décode aud et le compare à la configuration du serveur.
Pourquoi je ne désactive pas audience validation
Un issuer peut émettre des tokens pour plusieurs APIs. Sans contrôle d’audience, un token prévu pour Service A pourrait être accepté par Service B. RFC 8725 recommande de vérifier cette destination lorsque le profil l’utilise.
Un wildcard n’est donc pas une correction acceptable pour un mauvais paramétrage de resource.
Modifier aud ne répare pas un JWT signé
Changer le payload modifie les octets couverts par la signature. L’ancienne signature doit alors échouer.
Le correctif se trouve généralement dans :
- resource/audience demandée ;
- scopes ;
- audience attendue par l’API ;
- environnement/tenant ;
- choix Access Token vs ID Token.
Pour la couche cryptographique, j’utilise JWT Signature Verifier.
Ma matrice de décision
| Observation | Cause probable | Action |
|---|---|---|
aud = client ID | ID Token utilisé comme Access Token | vérifier le token envoyé |
aud = dev en prod | mélange d’environnements | corriger config client/API |
aud est un tableau | comparaison incorrecte | tester l’appartenance |
signature valide mais aud faux | mauvaise resource | demander un nouveau token |
iss et aud faux | mauvais tenant/issuer | vérifier discovery/config |
Mon workflow audience mismatch
- Je conserve le JWT original sans modification.
- Je lis
iss,aud,azp,scopeetexpavec JWT Decoder. - Je récupère l’Expected Audience dans la configuration de l’API.
- Je traite
audcorrectement comme chaîne ou tableau. - Je confirme qu’un Access Token est envoyé et non un ID Token.
- Je compare dev/staging/prod et tenant côté client et serveur.
- Je vérifie resource/scope/audience du token request.
- Je confirme l’issuer attendu et sa source de clés de confiance.
- Je vérifie la signature si nécessaire.
- Je corrige acquisition/configuration puis demande un nouveau token.
Si le problème dépasse aud, je poursuis avec le guide JWT 401. Un token authentique n’est pas automatiquement valable pour chaque destinataire.