Quando um JWT parece correto mas a API retorna invalid issuer, issuer mismatch ou um 401 depois da assinatura, trato iss como parte da fronteira de confiança, não como simples texto do payload.
Minha pergunta não é apenas “qual URL está em iss?”. É: esse é exatamente o issuer que a aplicação foi configurada para confiar e a assinatura foi verificada com chaves ligadas a esse issuer?
1. Leio iss sem confiar nele ainda
No Decodificador JWT, posso encontrar:
{
"iss": "https://login.example.com/",
"aud": "api://orders",
"exp": 1789203600
}
A RFC 7519 define iss como Issuer. Antes da verificação da assinatura, uso esse valor para diagnóstico, não como prova de origem.
Qualquer pessoa que fabrique um payload pode escrever uma URL conhecida em iss.
2. Identifico o issuer esperado pela API
Procuro uma única fonte autoritativa na configuração do resource server, por exemplo:
https://login.example.com/
Depois comparo o valor exato.
Diferenças aparentemente pequenas podem ser relevantes:
https://login.example.com
https://login.example.com/
https://login.example.com/tenant-a
https://login.example.com/tenant-b
Não removo barras, paths ou altero casing arbitrariamente a menos que o protocolo/perfil permita normalização.
Se conheço o valor esperado, o Depurador JWT faz essa comparação diretamente.
3. Verifico mistura de dev, staging e produção
Este é um dos erros que procuro primeiro:
Token iss: https://login.dev.example.com/
API espera: https://login.example.com/
Um token de outro ambiente pode trazer, ao mesmo tempo:
- issuer errado;
- audience errada;
kiddesconhecido;- assinatura que falha com o JWKS de produção;
- scopes diferentes.
Quando kid not found e issuer mismatch aparecem juntos, investigo ambiente antes de mexer no código criptográfico.
4. Ligo o issuer à origem das chaves
Essa é a parte mais importante.
A RFC 8414 define metadata de authorization server com um identificador issuer e, opcionalmente, jwks_uri.
A cadeia que quero é:
aplicação confia no issuer A
↓
metadata/configuração de A
↓
jwks_uri confiável de A
↓
JWK selecionada por kid
↓
assinatura verificada
Não quero:
JWT diz que iss=A
↓
JWT fornece origem de chave arbitrária
↓
assinatura passa com chave do atacante
A RFC 8725 reforça que, quando issuer faz parte do perfil, as chaves de verificação precisam pertencer ao issuer validado.
O Validador JWKS reflete esse modelo: sou eu quem fornece a origem JWKS confiável.
5. Verifico a assinatura antes de confiar no issuer autenticado
Se o JWT usa RS256 e kid aponta para uma chave do JWKS do issuer confiável, verifico a assinatura.
Se a chave não existe, sigo o guia de JWT kid. Se existe mas a assinatura falha, uso o guia de assinatura JWT inválida.
Issuer e assinatura trabalham juntos:
- configuração do issuer diz quais chaves são confiáveis;
- essas chaves autenticam o claim
issassinado.
6. Assinatura válida ainda não basta
Posso ter:
assinatura verificada ✓
iss esperado ✕
Ainda rejeito o token.
Um provedor pode atender vários tenants, aplicações ou perfis. Uma assinatura matematicamente válida não significa que o token pertence ao trust domain que minha API aceita.
7. Não confundo issuer com audience
Os claims respondem perguntas diferentes:
iss— quem emitiu?aud— para quem foi emitido?
Um JWT do issuer correto pode trazer:
{
"iss": "https://login.example.com/",
"aud": "api://billing"
}
e ainda ser errado para Orders.
Depois de issuer, valido audience, tempo, tipo do token e autorização. Se aud é o problema, sigo o guia de audience mismatch.
8. Multi-tenant exige política explícita
Em sistemas multi-tenant, verifico:
- cada tenant tem issuer próprio?
- o JWKS é compartilhado ou específico?
- mais de um issuer é intencionalmente aceito?
- existe allowlist explícita?
Evito aceitar qualquer issuer sob um hostname amplo apenas porque “parece do mesmo provedor”.
Se vários issuers são legítimos, associo cada um à política de metadata e descoberta apropriada.
O que não faço para corrigir issuer mismatch
- não desativo validação de issuer;
- não confio em qualquer issuer que produza uma assinatura válida;
- não baixo dinamicamente um JWKS só porque
issnão verificado aponta para ele; - não edito
issdentro do JWT; - não substituo validação de issuer por validação de audience.
Meu checklist de issuer JWT
- Decodifico
iss,kid,algeaud. - Encontro o issuer exato configurado na API.
- Checo ambiente e tenant.
- Obtenho metadata/JWKS por uma origem já confiável.
- Seleciono a chave por
kiddentro desse conjunto. - Verifico a assinatura.
- Comparo o
issautenticado com o issuer esperado. - Valido
aud,exp,nbfe o tipo de token. - Leio logs do servidor para identificar a comparação que falhou.
- Corrijo configuração/trust path sem tornar a validação permissiva.
A regra que sigo é: validar issuer não é apenas reconhecer uma URL no payload; é garantir que o JWT foi autenticado com chaves pertencentes a um emissor deliberadamente confiado pela aplicação e que o claim assinado corresponde exatamente a ele.