Pular para o conteúdo
ecdsa.com
PHP

firebase/php-jwt

O firebase/php-jwt, o pacote de JWT mais instalado para PHP: um objeto Key que fixa o algoritmo, chaves HMAC curtas recusadas, mas sem ES512 nem PS384/512, sem verificação de emissor ou de público-alvo e com ES256 aceito para chaves P-384.
Licença
BSD-3-Clause
Versão verificada
7.2.1 ·
Código-fonte
github.com/firebase/php-jwt
Documentação
github.com/firebase/php-jwt#readme

Visão geral da compatibilidade

JOSE e JWT

Algoritmos JWS
HS256HS384HS512RS256RS384RS512ES256ES384ES256KEdDSA

O php-jwt codifica e decodifica tokens com JWT::encode() e JWT::decode() sobre a extensão openssl e a libsodium. Desde a versão 6, um objeto Key — o material da chave mais o algoritmo — é obrigatório, então o algoritmo vem do seu código, e não do token: um token RS256 e um token HS256 forjado com o texto PEM da chave EC falharam contra new Key($pem, 'ES256') com Incorrect key for this algorithm, e um token sem assinatura falha com Algorithm not supported. A proteção depende inteiramente da Key que a aplicação monta: new Key($pem, 'HS256') verificou o token forjado.

A versão 7.2.1 trabalha com HS256/384/512, RS256/384/512, ES256, ES384, ES256K e EdDSA. Não há suporte a ES512 (Algorithm not supported), o PS256 exige o phpseclib/phpseclib instalado, e PS384 e PS512 simplesmente não estão disponíveis — tokens de emissores que usam esses algoritmos precisam do web-token ou do lcobucci/jwt. Chaves HMAC menores que o hash são rejeitadas (Provided key is too short).

O ES256 não fica restrito à P-256: um token assinado com uma chave P-384 sob um cabeçalho ES256 foi produzido e aceito pela própria biblioteca, embora outras bibliotecas o recusem. As assinaturas ES256 são convertidas no r‖s bruto de 64 bytes que o JWS exige; uma assinatura DER falha com Signature verification failed. Confira a assinatura de um token no depurador de JWT.

O tratamento das claims é mínimo. exp, nbf e iat só são verificadas quando presentes, JWT::$leeway é uma variável estática global com padrão 0, e não há nenhuma validação de emissor nem de público-alvo — o exemplo verifica exp e iss por conta própria. Para a verificação baseada em JWKS, JWK::parseKeySet() converte um conjunto de chaves em objetos Key; inspecione o conjunto de um provedor com o verificador de JWKS.

Os fatos e as verificações por trás deles

Nada abaixo foi copiado da documentação. A verificação content/libraries/verify/firebase-php-jwt/run.sh executou firebase/php-jwt 7.2.1 na imagem de contêiner php:8.5.11-cli-trixie em 20 de outubro de 2026; a página precisa corresponder ao que a verificação imprimiu, e cada fato lista essas linhas.

  • Algoritmos JWS

    HS256HS384HS512RS256RS384RS512ES256ES384ES256KEdDSA

    Assinatura e verificação funcionaram com HS256/384/512, RS256/384/512, ES256, ES384, ES256K e EdDSA; não há suporte a ES512 nem a PS384/512, e o PS256 exige o phpseclib.

    Registrado pela verificação
    fact jws-algorithms = HS256, HS384, HS512, RS256, RS384, RS512, ES256, ES384, ES256K, EdDSA
    evidence jws-algorithms: PS256: DomainException: phpseclib/phpseclib is required for PS256 support
    evidence jws-algorithms: PS384: DomainException: Algorithm not supported
    evidence jws-algorithms: PS512: DomainException: Algorithm not supported
    evidence jws-algorithms: ES512: DomainException: Algorithm not supported
    evidence jws-algorithms: Ed25519: no key family
  • Codificação da assinatura ES256

    raw

    As assinaturas ES256 são 64 bytes de r‖s brutos.

    Registrado pela verificação
    fact jws-ecdsa-encoding = raw
  • Assinatura DER dentro de um JWS

    rejected

    Uma assinatura ES256 codificada em DER falha com SignatureInvalidException: Signature verification failed.

    Registrado pela verificação
    fact jws-der-signature = rejected
    evidence jws-der-signature: Firebase\JWT\SignatureInvalidException: Signature verification failed
  • Lista de algoritmos permitidos

    required

    decode() exige um objeto Key com um algoritmo; uma string de chave pura falha, e um token RS256 verificado contra new Key($ecPem, 'ES256') falha com Incorrect key for this algorithm.

    Registrado pela verificação
    fact jwt-algorithm-allowlist = required
    evidence jwt-algorithm-allowlist: RS256 token against new Key(EC PEM, 'ES256'): UnexpectedValueException: Incorrect key for this algorithm
    evidence jwt-algorithm-allowlist: decode() with a bare key string: UnexpectedValueException: "kid" empty, unable to lookup correct key
  • Tokens sem assinatura (alg none)

    rejected

    Um token sem assinatura falha com Algorithm not supported.

    Registrado pela verificação
    fact jwt-alg-none = rejected
    evidence jwt-alg-none: UnexpectedValueException: Algorithm not supported
  • Chave pública usada como segredo HMAC

    rejected

    Um token HS256 que usava o texto PEM como chave falhou contra a Key ES256, mas new Key($pem, 'HS256') o verificou.

    Registrado pela verificação
    fact jwt-hmac-public-key = rejected
    evidence jwt-hmac-public-key: Key(PEM, 'ES256'): UnexpectedValueException: Incorrect key for this algorithm
    evidence jwt-hmac-public-key: Key(PEM, 'HS256') built by the application: ok
  • Curva conferida com o alg

    not-enforced

    Um token assinado como ES256 com uma chave P-384 foi produzido e verificado com sucesso.

    Registrado pela verificação
    fact jwt-ecdsa-curve-check = not-enforced
    evidence jwt-ecdsa-curve-check: ok
  • Tolerância padrão de diferença de relógio

    0s

    JWT::$leeway é 0: um token expirado três segundos antes foi rejeitado.

    Registrado pela verificação
    fact jwt-clock-skew = 0s
    evidence jwt-clock-skew: JWT::$leeway = 0
  • Claim de expiração obrigatória

    no

    Um token sem exp foi decodificado com sucesso.

    Registrado pela verificação
    fact jwt-exp-required = no
  • Segredo HMAC curto

    rejected

    Uma chave HS256 de 5 bytes falha com Provided key is too short.

    Registrado pela verificação
    fact jwt-hmac-short-secret = rejected
    evidence jwt-hmac-short-secret: 5-byte HS256 key: DomainException: Provided key is too short

Uso

Emita um token ES256, decodifique-o com uma Key que fixa o algoritmo e com 30 segundos de tolerância, e verifique exp e iss explicitamente.
<?php
require 'vendor/autoload.php';

use Firebase\JWT\JWT;
use Firebase\JWT\Key;

$private = openssl_pkey_new(['private_key_type' => OPENSSL_KEYTYPE_EC, 'curve_name' => 'prime256v1']);
$publicPem = openssl_pkey_get_details($private)['key'];

$token = JWT::encode(['sub' => 'user-42', 'iss' => 'https://auth.example.com', 'exp' => time() + 600], $private, 'ES256');

// The Key object pins the algorithm; leeway is a static setting, 0 by default.
JWT::$leeway = 30;
$claims = JWT::decode($token, new Key($publicPem, 'ES256'));

// php-jwt checks exp/nbf/iat only when present and never checks iss or aud: do it here.
if (!isset($claims->exp) || $claims->iss !== 'https://auth.example.com') {
    throw new UnexpectedValueException('unexpected claims');
}
echo 'sub: ', $claims->sub, "\n";

O executor de trechos de código roda cada exemplo literalmente na imagem de contêiner php:8.5.11-cli-trixie, e a execução falha se a saída não corresponder.

Configuração
curl -fsSL -o /tmp/composer.phar https://getcomposer.org/download/2.10.3/composer.phar && echo '7a2d379d5b8ffdaa028580ef26494c36d2feef4b178d3dd1473a4dbc5e17c8d6 /tmp/composer.phar' | sha256sum -c - >/dev/null && apt-get -qq update >/dev/null && apt-get -qq install -y unzip >/dev/null 2>&1 && COMPOSER_ALLOW_SUPERUSER=1 php /tmp/composer.phar require --quiet firebase/php-jwt:7.2.1
Comando
php usage.php
A saída deve corresponder a (expressão regular)
sub: user-42

Bibliotecas