composer require firebase/php-jwt:7.2.1<?phprequire __DIR__ . '/vendor/autoload.php'; use Firebase\JWT\JWT; $privateKey = file_get_contents('key.pem'); // PEM text: PKCS#8 or "EC PRIVATE KEY" $now = time();$token = JWT::encode( [ 'iss' => 'https://issuer.example.com', 'sub' => 'user-42', 'aud' => 'api://orders', 'iat' => $now, 'exp' => $now + 15 * 60, ], $privateKey, 'ES256', '2026-10', // kid);echo $token, PHP_EOL;How it works
composer require firebase/php-jwt:7.2.1installs the library;vendor/autoload.phploads it.- The key can be the PEM text (PKCS#8 or
EC PRIVATE KEY) or anOpenSSLAsymmetricKeyfromopenssl_pkey_get_private. - The fourth argument of
JWT::encodeis thekid; a fifth, optional array adds other header fields.typandalgare set automatically. - The result is the compact token string.
Gotchas
- php-jwt does not check the curve: a P-384 key with
'ES256'produces a token with a 96-byte signature that no ES256 verifier accepts. Generate P-256 keys for ES256 (prime256v1in OpenSSL terms). - A malformed key throws
DomainException: OpenSSL unable to validate key— often a PEM with lost line breaks after passing through an environment variable. - php-jwt keeps payload values as you give them:
time()returns an integer, but a float or a numeric string would end up in the token in that form. Buildiatandexpfrom integers. - Verify the result once with another implementation; signing code that has never been checked by an independent verifier is the usual source of tokens only the issuer itself accepts.