Guias JWT

JWT kid: Como Depurar a Seleção de Chave JWKS

Veja como depurar kid not found, seleção de JWK, rotação de chaves, alg, kty, use e origem confiável do JWKS sem tratar kid como prova de confiança.

Por JWTDecoder.toolsÚltima verificação em 2026-09-12

Voz editorial: a primeira pessoa descreve o fluxo de trabalho documentado do JWTDecoder.tools; JWTDecoder.tools é o editor e autor organizacional.

kid + alg → compatible JWK
trusted issuer → JWKS → kid + alg → JWK

Quando encontro kid not found, unknown key ID ou uma assinatura que começou a falhar depois de uma rotação, começo no cabeçalho do JWT. kid é a pista que costuma ligar o token a uma chave dentro de um JWKS.

Mas mantenho uma regra importante: kid ajuda a escolher uma chave; ele não torna essa chave confiável.

Se já tenho o token e o key set, uso o Validador JWKS para ver alg, kid e iss, selecionar uma JWK compatível e verificar a assinatura localmente.

1. Decodifico o cabeçalho e leio kid

Começo pelo Decodificador JWT:

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "2026-09-key-03"
}

A RFC 7515 define kid como Key ID. A RFC 7517 também usa kid em JWK e cita seleção de chaves inclusive durante rollover.

Trato esse valor como um identificador fornecido pelo token. Um atacante também pode escrever qualquer kid; por isso a confiança vem do issuer e da origem do JWKS, não do identificador isolado.

2. Uso o JWKS do issuer que a aplicação já confia

Um conjunto de chaves pode parecer assim:

{
  "keys": [
    {
      "kty": "RSA",
      "kid": "2026-09-key-03",
      "use": "sig",
      "alg": "RS256",
      "n": "...",
      "e": "AQAB"
    },
    {
      "kty": "RSA",
      "kid": "2026-06-key-02",
      "use": "sig",
      "alg": "RS256",
      "n": "...",
      "e": "AQAB"
    }
  ]
}

Comparo o kid com as chaves no conjunto que minha configuração já associa ao issuer confiável.

Não procuro na internet por “uma chave com o mesmo kid”. O identificador não é globalmente único.

Em deployments OAuth/OIDC, a cadeia que quero é:

issuer configurado
      ↓
metadata confiável
      ↓
jwks_uri confiável
      ↓
JWKS
      ↓
kid seleciona JWK

3. Se kid não existe no token

kid nem sempre é obrigatório.

Se o JWKS confiável contém exatamente uma chave compatível, o verifier pode ter uma regra determinística suficiente. Se existem várias chaves compatíveis e nenhum kid, trato a seleção como ambígua, a menos que o perfil da aplicação defina outro critério.

Não gosto de lógica “tente todas as chaves até alguma assinatura passar” quando não existe uma política clara para isso.

O Validador JWKS segue uma postura conservadora: sem kid e com várias candidatas compatíveis, informa seleção ambígua.

4. Depois do kid, verifico compatibilidade

Um match de identificador não encerra a checagem. Também olho:

  • JWT alg;
  • JWK kty;
  • JWK alg, quando presente;
  • use, quando presente;
  • key_ops, quando presente.

Um JWT RS256 precisa de material RSA adequado para verificação. Uma JWK marcada como use: "enc" não deve ser escolhida para verificar assinatura apenas porque kid coincide.

A RFC 8725 também recomenda restringir algoritmos aceitos na configuração da aplicação.

5. Se kid não é encontrado, penso em rotação

Um cenário comum:

issuer publica chave A
      ↓
tokens usam kid A
      ↓
issuer publica chave B
      ↓
novos tokens usam kid B
      ↓
verifier ainda tem JWKS em cache só com A

Então vejo kid B not found.

Verifico:

  1. o issuer já publica B?
  2. o verifier mantém cache JWKS?
  3. qual é o TTL?
  4. um miss de kid dispara refresh controlado?
  5. estou consultando o issuer/tenant/ambiente correto?

O guia de rotação de chaves JWT aprofunda a relação entre vida do token, overlap de chaves e cache.

6. Verifico ambiente e tenant

Muitos “kid not found” são, na verdade, configuração errada.

JWT iss:  https://login.dev.example.com/
API confia: https://login.example.com/

Dev e produção podem publicar key sets totalmente diferentes. Multi-tenant também pode ter issuer e JWKS específicos.

Por isso, quando kid não aparece, pergunto também: este token veio do issuer que eu realmente pretendia aceitar?

O fluxo de validação de issuer cobre essa relação.

7. Não sigo jku ou x5u automaticamente

Headers JOSE podem carregar URLs como jku ou x5u. Trato esses valores como entrada não confiável a menos que exista uma política explícita que restrinja as origens.

A RFC 8725 alerta para riscos de confiar cegamente em URLs controladas pelo token, inclusive SSRF e falhas de trust.

O Validador JWKS só carrega uma URL que o usuário informa explicitamente; ele não deixa o JWT escolher o servidor de chaves.

8. kid encontrado ainda não significa assinatura válida

Quero chegar a algo assim:

kid encontrado         ✓
alg/kty compatíveis    ✓
chave serve para sig   ✓
assinatura verificada  ✓ / ✕

Se os três primeiros passam e a assinatura falha, sigo o guia de assinatura JWT inválida.

9. Depois da assinatura, valido claims

Assinatura com a JWK correta ainda não significa “aceitar o token”. Continuo com:

  • iss;
  • aud;
  • exp;
  • nbf;
  • tipo/profile;
  • scopes e roles.

O mesmo issuer pode assinar tokens para várias APIs.

Meu checklist de kid

  1. Decodifico alg, kid e iss.
  2. Identifico o issuer confiável configurado.
  3. Obtenho JWKS pela cadeia de confiança desse issuer.
  4. Busco match exato de kid.
  5. Confiro kty, alg, use e key_ops.
  6. Se não existe, verifico rotação e cache.
  7. Verifico mistura de ambiente ou tenant.
  8. Não confio automaticamente em URL fornecida pelo token.
  9. Verifico a assinatura com a JWK selecionada.
  10. Valido issuer, audience e tempo depois.

O ponto principal permanece: kid é um mecanismo de seleção dentro de uma fonte de chaves que já precisa ser confiável.

Fontes e referências

Guias relacionados