Mensagem de erro
Firebase\JWT\SignatureInvalidException: Signature verification failed
Também aparece como
- PHP Fatal error: Uncaught Firebase\JWT\SignatureInvalidException: Signature verification failed
Sem tratamento, o PHP imprime “PHP Fatal error: Uncaught Firebase\JWT\SignatureInvalidException: Signature verification failed in …/JWT.php”.
firebase/php-jwt (PHP) — Firebase\JWT\SignatureInvalidException from JWT::decode
O que significa
O php-jwt analisou o token, aceitou o algoritmo para a chave que você passou, e a verificação da assinatura retornou false: a chave e o token não formam um par, ou o token foi alterado depois de assinado. `SignatureInvalidException` é uma subclasse de `UnexpectedValueException`, então um bloco catch genérico pode escondê-la entre os erros de parsing.
Por que acontece
A chave configurada não é a do signatário
comumUma chave pública copiada de outro ambiente, ou uma chave que foi rotacionada do lado do emissor. O Firebase Auth e o Google assinam tokens de ID com chaves que mudam a cada poucos dias.
Uma chave escolhida de um conjunto de chaves sem usar o kid
comumUm código que pega a primeira chave de um JWKS (por exemplo, `reset(JWK::parseKeySet($jwks))`) funciona até o emissor assinar com outra chave do conjunto.
O segredo HMAC é diferente entre os serviços
ocasionalNo HS256, qualquer diferença na string do segredo — espaços em branco, uma quebra de linha no final vinda de um arquivo, base64 de um lado e valor bruto do outro — produz um MAC diferente.
O token foi alterado depois de assinado
ocasionalCabeçalho ou payload recodificado, ou um token montado com partes de dois tokens.
Como corrigir
- 1.
Passar o conjunto de chaves inteiro e deixar o php-jwt escolher pelo kid
`JWT::decode` aceita um array de objetos `Key` indexado por `kid` (vindo de `JWK::parseKeySet`) ou um `CachedKeySet`, que também se atualiza quando há rotação.
php use Firebase\JWT\CachedKeySet; use Firebase\JWT\JWT; use GuzzleHttp\Client; use GuzzleHttp\Psr7\HttpFactory; // Keys selected by the token's kid, fetched from the issuer's JWKS and cached (PSR-6). $keys = new CachedKeySet( 'https://issuer.example.com/.well-known/jwks.json', new Client(), new HttpFactory(), $cache, // any PSR-6 cache pool 3600, // cache lifetime in seconds true // rate-limit refetches on unknown kids ); $claims = JWT::decode($token, $keys); - 2.
Comparar as metades do par de chaves
Se a chave pública derivada da chave privada do emissor for diferente da que você configurou, a verificação da assinatura não tem como dar certo.
bash # Do the issuer's private key and your public key belong together? openssl pkey -in issuer-private.pem -pubout | sha256sum openssl pkey -pubin -in configured-public.pem | sha256sum