1![Build Status](https://github.com/firebase/php-jwt/actions/workflows/tests.yml/badge.svg) 2[![Latest Stable Version](https://poser.pugx.org/firebase/php-jwt/v/stable)](https://packagist.org/packages/firebase/php-jwt) 3[![Total Downloads](https://poser.pugx.org/firebase/php-jwt/downloads)](https://packagist.org/packages/firebase/php-jwt) 4[![License](https://poser.pugx.org/firebase/php-jwt/license)](https://packagist.org/packages/firebase/php-jwt) 5 6PHP-JWT 7======= 8A simple library to encode and decode JSON Web Tokens (JWT) in PHP, conforming to [RFC 7519](https://tools.ietf.org/html/rfc7519). 9 10Installation 11------------ 12 13Use composer to manage your dependencies and download PHP-JWT: 14 15```bash 16composer require firebase/php-jwt 17``` 18 19Optionally, install the `paragonie/sodium_compat` package from composer if your 20php is < 7.2 or does not have libsodium installed: 21 22```bash 23composer require paragonie/sodium_compat 24``` 25 26Example 27------- 28```php 29use Firebase\JWT\JWT; 30use Firebase\JWT\Key; 31 32$key = "example_key"; 33$payload = array( 34 "iss" => "http://example.org", 35 "aud" => "http://example.com", 36 "iat" => 1356999524, 37 "nbf" => 1357000000 38); 39 40/** 41 * IMPORTANT: 42 * You must specify supported algorithms for your application. See 43 * https://tools.ietf.org/html/draft-ietf-jose-json-web-algorithms-40 44 * for a list of spec-compliant algorithms. 45 */ 46$jwt = JWT::encode($payload, $key, 'HS256'); 47$decoded = JWT::decode($jwt, new Key($key, 'HS256')); 48 49print_r($decoded); 50 51/* 52 NOTE: This will now be an object instead of an associative array. To get 53 an associative array, you will need to cast it as such: 54*/ 55 56$decoded_array = (array) $decoded; 57 58/** 59 * You can add a leeway to account for when there is a clock skew times between 60 * the signing and verifying servers. It is recommended that this leeway should 61 * not be bigger than a few minutes. 62 * 63 * Source: http://self-issued.info/docs/draft-ietf-oauth-json-web-token.html#nbfDef 64 */ 65JWT::$leeway = 60; // $leeway in seconds 66$decoded = JWT::decode($jwt, new Key($key, 'HS256')); 67``` 68Example with RS256 (openssl) 69---------------------------- 70```php 71use Firebase\JWT\JWT; 72use Firebase\JWT\Key; 73 74$privateKey = <<<EOD 75-----BEGIN RSA PRIVATE KEY----- 76MIICXAIBAAKBgQC8kGa1pSjbSYZVebtTRBLxBz5H4i2p/llLCrEeQhta5kaQu/Rn 77vuER4W8oDH3+3iuIYW4VQAzyqFpwuzjkDI+17t5t0tyazyZ8JXw+KgXTxldMPEL9 785+qVhgXvwtihXC1c5oGbRlEDvDF6Sa53rcFVsYJ4ehde/zUxo6UvS7UrBQIDAQAB 79AoGAb/MXV46XxCFRxNuB8LyAtmLDgi/xRnTAlMHjSACddwkyKem8//8eZtw9fzxz 80bWZ/1/doQOuHBGYZU8aDzzj59FZ78dyzNFoF91hbvZKkg+6wGyd/LrGVEB+Xre0J 81Nil0GReM2AHDNZUYRv+HYJPIOrB0CRczLQsgFJ8K6aAD6F0CQQDzbpjYdx10qgK1 82cP59UHiHjPZYC0loEsk7s+hUmT3QHerAQJMZWC11Qrn2N+ybwwNblDKv+s5qgMQ5 835tNoQ9IfAkEAxkyffU6ythpg/H0Ixe1I2rd0GbF05biIzO/i77Det3n4YsJVlDck 84ZkcvY3SK2iRIL4c9yY6hlIhs+K9wXTtGWwJBAO9Dskl48mO7woPR9uD22jDpNSwe 85k90OMepTjzSvlhjbfuPN1IdhqvSJTDychRwn1kIJ7LQZgQ8fVz9OCFZ/6qMCQGOb 86qaGwHmUK6xzpUbbacnYrIM6nLSkXgOAwv7XXCojvY614ILTK3iXiLBOxPu5Eu13k 87eUz9sHyD6vkgZzjtxXECQAkp4Xerf5TGfQXGXhxIX52yH+N2LtujCdkQZjXAsGdm 88B2zNzvrlgRmgBrklMTrMYgm1NPcW+bRLGcwgW2PTvNM= 89-----END RSA PRIVATE KEY----- 90EOD; 91 92$publicKey = <<<EOD 93-----BEGIN PUBLIC KEY----- 94MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC8kGa1pSjbSYZVebtTRBLxBz5H 954i2p/llLCrEeQhta5kaQu/RnvuER4W8oDH3+3iuIYW4VQAzyqFpwuzjkDI+17t5t 960tyazyZ8JXw+KgXTxldMPEL95+qVhgXvwtihXC1c5oGbRlEDvDF6Sa53rcFVsYJ4 97ehde/zUxo6UvS7UrBQIDAQAB 98-----END PUBLIC KEY----- 99EOD; 100 101$payload = array( 102 "iss" => "example.org", 103 "aud" => "example.com", 104 "iat" => 1356999524, 105 "nbf" => 1357000000 106); 107 108$jwt = JWT::encode($payload, $privateKey, 'RS256'); 109echo "Encode:\n" . print_r($jwt, true) . "\n"; 110 111$decoded = JWT::decode($jwt, new Key($publicKey, 'RS256')); 112 113/* 114 NOTE: This will now be an object instead of an associative array. To get 115 an associative array, you will need to cast it as such: 116*/ 117 118$decoded_array = (array) $decoded; 119echo "Decode:\n" . print_r($decoded_array, true) . "\n"; 120``` 121 122Example with a passphrase 123------------------------- 124 125```php 126use Firebase\JWT\JWT; 127use Firebase\JWT\Key; 128 129// Your passphrase 130$passphrase = '[YOUR_PASSPHRASE]'; 131 132// Your private key file with passphrase 133// Can be generated with "ssh-keygen -t rsa -m pem" 134$privateKeyFile = '/path/to/key-with-passphrase.pem'; 135 136// Create a private key of type "resource" 137$privateKey = openssl_pkey_get_private( 138 file_get_contents($privateKeyFile), 139 $passphrase 140); 141 142$payload = array( 143 "iss" => "example.org", 144 "aud" => "example.com", 145 "iat" => 1356999524, 146 "nbf" => 1357000000 147); 148 149$jwt = JWT::encode($payload, $privateKey, 'RS256'); 150echo "Encode:\n" . print_r($jwt, true) . "\n"; 151 152// Get public key from the private key, or pull from from a file. 153$publicKey = openssl_pkey_get_details($privateKey)['key']; 154 155$decoded = JWT::decode($jwt, new Key($publicKey, 'RS256')); 156echo "Decode:\n" . print_r((array) $decoded, true) . "\n"; 157``` 158 159Example with EdDSA (libsodium and Ed25519 signature) 160---------------------------- 161```php 162use Firebase\JWT\JWT; 163use Firebase\JWT\Key; 164 165// Public and private keys are expected to be Base64 encoded. The last 166// non-empty line is used so that keys can be generated with 167// sodium_crypto_sign_keypair(). The secret keys generated by other tools may 168// need to be adjusted to match the input expected by libsodium. 169 170$keyPair = sodium_crypto_sign_keypair(); 171 172$privateKey = base64_encode(sodium_crypto_sign_secretkey($keyPair)); 173 174$publicKey = base64_encode(sodium_crypto_sign_publickey($keyPair)); 175 176$payload = array( 177 "iss" => "example.org", 178 "aud" => "example.com", 179 "iat" => 1356999524, 180 "nbf" => 1357000000 181); 182 183$jwt = JWT::encode($payload, $privateKey, 'EdDSA'); 184echo "Encode:\n" . print_r($jwt, true) . "\n"; 185 186$decoded = JWT::decode($jwt, new Key($publicKey, 'EdDSA')); 187echo "Decode:\n" . print_r((array) $decoded, true) . "\n"; 188```` 189 190Using JWKs 191---------- 192 193```php 194use Firebase\JWT\JWK; 195use Firebase\JWT\JWT; 196 197// Set of keys. The "keys" key is required. For example, the JSON response to 198// this endpoint: https://www.gstatic.com/iap/verify/public_key-jwk 199$jwks = ['keys' => []]; 200 201// JWK::parseKeySet($jwks) returns an associative array of **kid** to Firebase\JWT\Key 202// objects. Pass this as the second parameter to JWT::decode. 203JWT::decode($payload, JWK::parseKeySet($jwks)); 204``` 205 206Miscellaneous 207------------- 208 209#### Casting to array 210 211The return value of `JWT::decode` is the generic PHP object `stdClass`. If you'd like to handle with arrays 212instead, you can do the following: 213 214```php 215// return type is stdClass 216$decoded = JWT::decode($payload, $keys); 217 218// cast to array 219$decoded = json_decode(json_encode($decoded), true); 220``` 221 222Changelog 223--------- 224 225#### 6.1.0 / 2022-03-23 226 227 - Drop support for PHP 5.3, 5.4, 5.5, 5.6, and 7.0 228 - Add parameter typing and return types where possible 229 230#### 6.0.0 / 2022-01-24 231 232 - **Backwards-Compatibility Breaking Changes**: See the [Release Notes](https://github.com/firebase/php-jwt/releases/tag/v6.0.0) for more information. 233 - New Key object to prevent key/algorithm type confusion (#365) 234 - Add JWK support (#273) 235 - Add ES256 support (#256) 236 - Add ES384 support (#324) 237 - Add Ed25519 support (#343) 238 239#### 5.0.0 / 2017-06-26 240- Support RS384 and RS512. 241 See [#117](https://github.com/firebase/php-jwt/pull/117). Thanks [@joostfaassen](https://github.com/joostfaassen)! 242- Add an example for RS256 openssl. 243 See [#125](https://github.com/firebase/php-jwt/pull/125). Thanks [@akeeman](https://github.com/akeeman)! 244- Detect invalid Base64 encoding in signature. 245 See [#162](https://github.com/firebase/php-jwt/pull/162). Thanks [@psignoret](https://github.com/psignoret)! 246- Update `JWT::verify` to handle OpenSSL errors. 247 See [#159](https://github.com/firebase/php-jwt/pull/159). Thanks [@bshaffer](https://github.com/bshaffer)! 248- Add `array` type hinting to `decode` method 249 See [#101](https://github.com/firebase/php-jwt/pull/101). Thanks [@hywak](https://github.com/hywak)! 250- Add all JSON error types. 251 See [#110](https://github.com/firebase/php-jwt/pull/110). Thanks [@gbalduzzi](https://github.com/gbalduzzi)! 252- Bugfix 'kid' not in given key list. 253 See [#129](https://github.com/firebase/php-jwt/pull/129). Thanks [@stampycode](https://github.com/stampycode)! 254- Miscellaneous cleanup, documentation and test fixes. 255 See [#107](https://github.com/firebase/php-jwt/pull/107), [#115](https://github.com/firebase/php-jwt/pull/115), 256 [#160](https://github.com/firebase/php-jwt/pull/160), [#161](https://github.com/firebase/php-jwt/pull/161), and 257 [#165](https://github.com/firebase/php-jwt/pull/165). Thanks [@akeeman](https://github.com/akeeman), 258 [@chinedufn](https://github.com/chinedufn), and [@bshaffer](https://github.com/bshaffer)! 259 260#### 4.0.0 / 2016-07-17 261- Add support for late static binding. See [#88](https://github.com/firebase/php-jwt/pull/88) for details. Thanks to [@chappy84](https://github.com/chappy84)! 262- Use static `$timestamp` instead of `time()` to improve unit testing. See [#93](https://github.com/firebase/php-jwt/pull/93) for details. Thanks to [@josephmcdermott](https://github.com/josephmcdermott)! 263- Fixes to exceptions classes. See [#81](https://github.com/firebase/php-jwt/pull/81) for details. Thanks to [@Maks3w](https://github.com/Maks3w)! 264- Fixes to PHPDoc. See [#76](https://github.com/firebase/php-jwt/pull/76) for details. Thanks to [@akeeman](https://github.com/akeeman)! 265 266#### 3.0.0 / 2015-07-22 267- Minimum PHP version updated from `5.2.0` to `5.3.0`. 268- Add `\Firebase\JWT` namespace. See 269[#59](https://github.com/firebase/php-jwt/pull/59) for details. Thanks to 270[@Dashron](https://github.com/Dashron)! 271- Require a non-empty key to decode and verify a JWT. See 272[#60](https://github.com/firebase/php-jwt/pull/60) for details. Thanks to 273[@sjones608](https://github.com/sjones608)! 274- Cleaner documentation blocks in the code. See 275[#62](https://github.com/firebase/php-jwt/pull/62) for details. Thanks to 276[@johanderuijter](https://github.com/johanderuijter)! 277 278#### 2.2.0 / 2015-06-22 279- Add support for adding custom, optional JWT headers to `JWT::encode()`. See 280[#53](https://github.com/firebase/php-jwt/pull/53/files) for details. Thanks to 281[@mcocaro](https://github.com/mcocaro)! 282 283#### 2.1.0 / 2015-05-20 284- Add support for adding a leeway to `JWT:decode()` that accounts for clock skew 285between signing and verifying entities. Thanks to [@lcabral](https://github.com/lcabral)! 286- Add support for passing an object implementing the `ArrayAccess` interface for 287`$keys` argument in `JWT::decode()`. Thanks to [@aztech-dev](https://github.com/aztech-dev)! 288 289#### 2.0.0 / 2015-04-01 290- **Note**: It is strongly recommended that you update to > v2.0.0 to address 291 known security vulnerabilities in prior versions when both symmetric and 292 asymmetric keys are used together. 293- Update signature for `JWT::decode(...)` to require an array of supported 294 algorithms to use when verifying token signatures. 295 296 297Tests 298----- 299Run the tests using phpunit: 300 301```bash 302$ pear install PHPUnit 303$ phpunit --configuration phpunit.xml.dist 304PHPUnit 3.7.10 by Sebastian Bergmann. 305..... 306Time: 0 seconds, Memory: 2.50Mb 307OK (5 tests, 5 assertions) 308``` 309 310New Lines in private keys 311----- 312 313If your private key contains `\n` characters, be sure to wrap it in double quotes `""` 314and not single quotes `''` in order to properly interpret the escaped characters. 315 316License 317------- 318[3-Clause BSD](http://opensource.org/licenses/BSD-3-Clause). 319