Quando encontro JWK e JWKS na documentação de JWT, uso um modelo simples:
JWK é uma chave criptográfica representada em JSON. JWKS é um objeto que contém um conjunto de JWKs.
A diferença parece pequena até entrar em cena kid, rotação de chaves, vários algoritmos ou um jwks_uri publicado pelo issuer.
Se já tenho um JWT e um conjunto de chaves, uso o Validador JWKS porque ele reproduz o fluxo que quero em uma aplicação: ler kid, selecionar uma JWK compatível dentro de um conjunto confiável e verificar a assinatura.
O que é JWK
A RFC 7517 define JSON Web Key (JWK) como uma representação JSON de uma chave criptográfica.
Uma chave pública RSA pode parecer:
{
"kty": "RSA",
"kid": "signing-key-2026-09",
"use": "sig",
"alg": "RS256",
"n": "...",
"e": "AQAB"
}
Ao ler esse objeto, observo:
kty— tipo da chave;kid— identificador;use— uso de alto nível, como assinatura;key_ops— operações permitidas, quando informado;alg— algoritmo associado, quando informado;- material de chave como
n/epara RSA oucrv/x/ypara EC.
Uma JWK bem formada não é automaticamente confiável. Preciso saber de onde ela veio e para qual issuer minha aplicação a aceita.
O que é JWKS
A RFC 7517 define um JWK Set como um objeto com um array keys contendo JWKs:
{
"keys": [
{
"kty": "RSA",
"kid": "key-old",
"use": "sig",
"alg": "RS256",
"n": "...",
"e": "AQAB"
},
{
"kty": "RSA",
"kid": "key-new",
"use": "sig",
"alg": "RS256",
"n": "...",
"e": "AQAB"
}
]
}
Na prática de desenvolvimento, esse conjunto é chamado de JWKS — JSON Web Key Set.
Minha regra de memória é:
JWK = uma chave
JWKS = um conjunto de chaves
Por que encontro JWKS com tanta frequência
Sistemas reais precisam lidar com:
- rotação de chaves;
- mais de uma chave ativa;
- tipos de chave diferentes;
- algoritmos diferentes;
- overlap entre chave antiga e nova.
JWKS permite publicar várias chaves públicas ao mesmo tempo.
Por isso um JWT pode trazer:
{
"alg": "RS256",
"kid": "key-new"
}
Uso kid para selecionar uma candidata dentro do conjunto confiável.
Como kid participa da seleção
Meu fluxo é:
JWT header kid
↓
JWKS do issuer confiável
↓
JWK com kid correspondente
↓
validar kty / alg / use / key_ops
↓
importar chave
↓
verificar assinatura
Não paro no match de kid. O guia de JWT kid mostra o que faço quando o identificador está ausente, duplicado, não existe ou ficou desatualizado após rotação.
Quando uso uma JWK individual
Uma única JWK é suficiente quando:
- já selecionei a chave exata de um conjunto confiável;
- uma configuração armazena uma chave pública em JSON;
- quero importar uma chave específica na Web Crypto API ou em uma biblioteca JOSE;
- estou depurando parâmetros de uma chave RSA ou EC.
O Web Crypto pode importar uma JWK pública compatível diretamente:
const publicKey = await crypto.subtle.importKey(
"jwk",
jwk,
{
name: "RSASSA-PKCS1-v1_5",
hash: "SHA-256"
},
false,
["verify"]
);
O ponto de segurança é anterior à importação: a aplicação já precisa ter selecionado essa JWK a partir de uma fonte confiável.
Quando mantenho o JWKS completo
Guardo o conjunto enquanto ainda preciso resolver seleção de chave, por exemplo:
- issuer que faz rotação;
- tokens com
kiddiferentes; - refresh quando aparece um
kiddesconhecido; - período de overlap entre chaves antigas e novas;
- resource server que valida tokens continuamente.
O guia de rotação de chaves JWT mostra por que duas JWKs podem precisar coexistir por algum tempo.
O que é jwks_uri
A RFC 8414 define jwks_uri em metadata de authorization server como a URL do JWK Set.
Exemplo:
{
"issuer": "https://login.example.com/",
"jwks_uri": "https://login.example.com/.well-known/jwks.json"
}
Eu uso essa relação como cadeia de confiança:
issuer configurado/confiável
↓
metadata confiável
↓
jwks_uri
↓
JWKS
↓
JWK selecionada por kid
Não inverto a lógica dizendo “o token trouxe uma URL, então vou confiar nas chaves de lá”.
JWK versus PEM
JWK é uma representação JSON de material de chave. PEM é uma representação textual muito usada para estruturas ASN.1 de chaves e certificados.
A mesma chave pública RSA pode frequentemente aparecer como:
-----BEGIN PUBLIC KEY-----
...
-----END PUBLIC KEY-----
ou como JWK com kty, n e e.
Escolho o formato de acordo com a integração. Muitos identity providers publicam JWKS; várias bibliotecas de servidor aceitam PEM; Web Crypto lida bem com import de JWK.
O formato muda. A decisão de confiança não.
Por que use, key_ops e alg importam
Quando presentes, esses metadados ajudam a impedir seleção sem sentido.
Para verificação posso encontrar:
{
"use": "sig",
"key_ops": ["verify"],
"alg": "RS256"
}
Se uma chave declara use: "enc", não a escolho para verificar assinatura só porque o kid coincide.
O modelo durante rotação
Antes:
JWKS
└── JWK A
Durante overlap:
JWKS
├── JWK A (antiga)
└── JWK B (nova)
Depois:
JWKS
└── JWK B
kid ajuda o verifier a escolher a JWK correta enquanto tokens de gerações diferentes coexistem.
Meu checklist antes de confiar em uma JWK
- Confirmo o issuer que a aplicação confia.
- Obtenho o JWKS da origem configurada/derivada de metadata confiável.
- Leio
kidcomo dica de seleção. - Encontro a JWK candidata.
- Confiro
kty,alg,useekey_opsquando presentes. - Importo com o algoritmo esperado pela aplicação.
- Verifico a assinatura.
- Depois valido issuer, audience, expiração e tipo do token.
A forma mais curta de lembrar é: JWK é a chave; JWKS é o chaveiro; kid ajuda a escolher qual chave do chaveiro tentar. E esse chaveiro precisa vir de um issuer que eu já confio.