diff --git a/README.md b/README.md index e4152cb..a12e7a4 100644 --- a/README.md +++ b/README.md @@ -127,17 +127,26 @@ $app->add(new Tuupola\Middleware\JwtAuthentication([ ### Algorithm -You can set supported algorithms via `algorithm` parameter. This can be either string or array of strings. Default value is `["HS256", "HS512", "HS384"]`. Supported algorithms are `HS256`, `HS384`, `HS512` and `RS256`. Note that enabling both `HS256` and `RS256` is a [security risk](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/). +You can set supported algorithms via `algorithm` parameter. This can be either string or array of strings. Default value is `["HS256"]`. Supported algorithms are `HS256`, `HS384`, `HS512` and `RS256`. Note that enabling both `HS256` and `RS256` is a [security risk](https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/). + +When passing multiple algorithm it be a key value array, with the key being the `KID` of the jwt. ``` php $app = new Slim\App; $app->add(new Tuupola\Middleware\JwtAuthentication([ "secret" => "supersecretkeyyoushouldnotcommittogithub", - "algorithm" => ["HS256", "HS384"] + "algorithm" => [ + "amce" => "HS256", + "beta" => "HS384" + ] ])); ``` +> :warning: **Warning**:
+Because of changes in `firebase/php-jwt` the `kid` is now checked when multiple algorithm are passed, failing to provide a key the algorithm will be used for the kid. +this also means the `kid` will now need to be present in the JWT header as well. + ### Attribute When the token is decoded successfully and authentication succeeds the contents of the decoded token is saved as `token` attribute to the `$request` object. You can change this with. `attribute` parameter. Set to `null` or `false` to disable this behavour diff --git a/src/JwtAuthentication.php b/src/JwtAuthentication.php index 444ddcb..0faab67 100644 --- a/src/JwtAuthentication.php +++ b/src/JwtAuthentication.php @@ -79,7 +79,7 @@ final class JwtAuthentication implements MiddlewareInterface * Stores all the options passed to the middleware. * * @var array{ - * secret?: string|array, + * secret?: string|array|array, * secure: bool, * relaxed: array, * algorithm: array, @@ -321,7 +321,8 @@ private function decodeToken(string $token): array try { $decoded = JWT::decode( $token, - $keys + $keys, + $this->options['algorithm'] ); return (array) $decoded; } catch (Exception $exception) { diff --git a/tests/JwtAuthenticationTest.php b/tests/JwtAuthenticationTest.php index 3e0e925..9f232f6 100644 --- a/tests/JwtAuthenticationTest.php +++ b/tests/JwtAuthenticationTest.php @@ -220,6 +220,33 @@ public function testShouldReturn200WithSecretArray(): void $this->assertEquals("Success", $response->getBody()); } + public function testShouldReturn200WithSecretArrayCheckKid(): void + { + $request = (new ServerRequestFactory) + ->createServerRequest("GET", "https://example.com/api") + ->withHeader("Authorization", "Bearer " . self::$betaToken); + + $default = function (ServerRequestInterface $request) { + $response = (new ResponseFactory)->createResponse(); + $response->getBody()->write("Success"); + return $response; + }; + + $collection = new MiddlewareCollection([ + new JwtAuthentication([ + "algorithm" => ["acme" => "HS256", "beta" => "HS256"], + "secret" => [ + "acme" =>"supersecretkeyyoushouldnotcommittogithub", + "beta" =>"anothersecretkeyfornevertocommittogithub" + ], + ]) + ]); + + $response = $collection->dispatch($request, $default); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals("Success", $response->getBody()); + } + public function testShouldReturn401WithSecretArray(): void { $request = (new ServerRequestFactory)