Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
lleyton committed Jun 14, 2023
2 parents a236a7a + 71278f2 commit 78fb9b5
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 6 deletions.
19 changes: 19 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,24 @@
# Changelog

## [6.7.0](https://github.com/firebase/php-jwt/compare/v6.6.0...v6.7.0) (2023-06-14)


### Features

* add ed25519 support to JWK (public keys) ([#452](https://github.com/firebase/php-jwt/issues/452)) ([e53979a](https://github.com/firebase/php-jwt/commit/e53979abae927de916a75b9d239cfda8ce32be2a))

## [6.6.0](https://github.com/firebase/php-jwt/compare/v6.5.0...v6.6.0) (2023-06-13)


### Features

* allow get headers when decoding token ([#442](https://github.com/firebase/php-jwt/issues/442)) ([fb85f47](https://github.com/firebase/php-jwt/commit/fb85f47cfaeffdd94faf8defdf07164abcdad6c3))


### Bug Fixes

* only check iat if nbf is not used ([#493](https://github.com/firebase/php-jwt/issues/493)) ([398ccd2](https://github.com/firebase/php-jwt/commit/398ccd25ea12fa84b9e4f1085d5ff448c21ec797))

## [6.5.0](https://github.com/firebase/php-jwt/compare/v6.4.0...v6.5.0) (2023-05-12)


Expand Down
5 changes: 4 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,12 @@ $payload = [
*/
$jwt = JWT::encode($payload, $key, 'HS256');
$decoded = JWT::decode($jwt, new Key($key, 'HS256'));

print_r($decoded);

// Pass a stdClass in as the third parameter to get the decoded header values
$decoded = JWT::decode($jwt, new Key($key, 'HS256'), $headers = new stdClass());
print_r($headers);

/*
NOTE: This will now be an object instead of an associative array. To get
an associative array, you will need to cast it as such:
Expand Down
28 changes: 27 additions & 1 deletion src/JWK.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ class JWK
// 'P-521' => '1.3.132.0.35', // Len: 132 (not supported)
];

// For keys with "kty" equal to "OKP" (Octet Key Pair), the "crv" parameter must contain the key subtype.
// This library supports the following subtypes:
private const OKP_SUBTYPES = [
'Ed25519' => true, // RFC 8037
];

/**
* Parse a set of JWK keys
*
Expand Down Expand Up @@ -145,8 +151,28 @@ public static function parseKey(array $jwk, string $defaultAlg = null): ?Key

$publicKey = self::createPemFromCrvAndXYCoordinates($jwk['crv'], $jwk['x'], $jwk['y']);
return new Key($publicKey, $jwk['alg']);
case 'OKP':
if (isset($jwk['d'])) {
// The key is actually a private key
throw new UnexpectedValueException('Key data must be for a public key');
}

if (!isset($jwk['crv'])) {
throw new UnexpectedValueException('crv not set');
}

if (empty(self::OKP_SUBTYPES[$jwk['crv']])) {
throw new DomainException('Unrecognised or unsupported OKP key subtype');
}

if (empty($jwk['x'])) {
throw new UnexpectedValueException('x not set');
}

// This library works internally with EdDSA keys (Ed25519) encoded in standard base64.
$publicKey = JWT::convertBase64urlToBase64($jwk['x']);
return new Key($publicKey, $jwk['alg']);
default:
// Currently only RSA is supported
break;
}

Expand Down
28 changes: 24 additions & 4 deletions src/JWT.php
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ class JWT
* Supported algorithms are 'ES384','ES256',
* 'HS256', 'HS384', 'HS512', 'RS256', 'RS384'
* and 'RS512'.
* @param stdClass $headers Optional. Populates stdClass with headers.
*
* @return stdClass The JWT's payload as a PHP object
*
Expand All @@ -94,7 +95,8 @@ class JWT
*/
public static function decode(
string $jwt,
$keyOrKeyArray
$keyOrKeyArray,
stdClass &$headers = null
): stdClass {
// Validate JWT
$timestamp = \is_null(static::$timestamp) ? \time() : static::$timestamp;
Expand All @@ -111,6 +113,9 @@ public static function decode(
if (null === ($header = static::jsonDecode($headerRaw))) {
throw new UnexpectedValueException('Invalid header encoding');
}
if ($headers !== null) {
$headers = $header;
}
$payloadRaw = static::urlsafeB64Decode($bodyb64);
if (null === ($payload = static::jsonDecode($payloadRaw))) {
throw new UnexpectedValueException('Invalid claims encoding');
Expand Down Expand Up @@ -215,7 +220,7 @@ public static function encode(
*
* @param string $msg The message to sign
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $key The secret key.
* @param string $alg Supported algorithms are 'ES384','ES256', 'ES256K', 'HS256',
* @param string $alg Supported algorithms are 'EdDSA', 'ES384', 'ES256', 'ES256K', 'HS256',
* 'HS384', 'HS512', 'RS256', 'RS384', and 'RS512'
*
* @return string An encrypted message
Expand Down Expand Up @@ -278,7 +283,7 @@ public static function sign(
*
* @param string $msg The original message (header and body)
* @param string $signature The original signature
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial For HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey
* @param string|resource|OpenSSLAsymmetricKey|OpenSSLCertificate $keyMaterial For Ed*, ES*, HS*, a string key works. for RS*, must be an instance of OpenSSLAsymmetricKey
* @param string $alg The algorithm
*
* @return bool
Expand Down Expand Up @@ -399,13 +404,28 @@ public static function jsonEncode(array $input): string
* @throws InvalidArgumentException invalid base64 characters
*/
public static function urlsafeB64Decode(string $input): string
{
return \base64_decode(self::convertBase64UrlToBase64($input));
}

/**
* Convert a string in the base64url (URL-safe Base64) encoding to standard base64.
*
* @param string $input A Base64 encoded string with URL-safe characters (-_ and no padding)
*
* @return string A Base64 encoded string with standard characters (+/) and padding (=), when
* needed.
*
* @see https://www.rfc-editor.org/rfc/rfc4648
*/
public static function convertBase64UrlToBase64(string $input): string
{
$remainder = \strlen($input) % 4;
if ($remainder) {
$padlen = 4 - $remainder;
$input .= \str_repeat('=', $padlen);
}
return \base64_decode(\strtr($input, '-_', '+/'));
return \strtr($input, '-_', '+/');
}

/**
Expand Down
15 changes: 15 additions & 0 deletions tests/JWTTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -397,4 +397,19 @@ public function testEncodeDecodeWithResource()

$this->assertSame('bar', $decoded->foo);
}

public function testGetHeaders()
{
$payload = [
'message' => 'abc',
'exp' => time() + JWT::$leeway + 20, // time in the future
];
$headers = new stdClass();

$encoded = JWT::encode($payload, 'my_key', 'HS256');
JWT::decode($encoded, new Key('my_key', 'HS256'), $headers);

$this->assertEquals($headers->typ, 'JWT');
$this->assertEquals($headers->alg, 'HS256');
}
}
11 changes: 11 additions & 0 deletions tests/data/ed25519-jwkset.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"keys": [
{
"kid": "jwk1",
"alg": "EdDSA",
"kty": "OKP",
"crv": "Ed25519",
"x": "uOSJMhbKSG4V5xUHS7B9YHmVg_1yVd-G-Io6oBFhSfY"
}
]
}

0 comments on commit 78fb9b5

Please sign in to comment.