Last active
August 24, 2021 12:51
-
-
Save settermjd/268d4eedb6b13bf9d70feb192e37823b to your computer and use it in GitHub Desktop.
Create and validate a JWT in Mezzio (PHP)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// File location: config/autoload/auth.global.php | |
return [ | |
'auth' => [ | |
'jwt' => [ | |
// A secret key that you've generated in some secure/random fashion. | |
'key' => 'XicRF1ZLIUc+NzB4uqdaVlyVNSucfR90kmoAiuOGRi0=', | |
'claim' => [ | |
'iss' => 'https:localdomain.dev', | |
'aud' => 'https:localdomain.dev', | |
], | |
// A DateTime interval dictating how long the token should be valid for | |
'expiryPeriod' => 'P10D', | |
'leeway' => 60, | |
'allowedAlgorithms' => [ | |
'HS256' | |
] | |
] | |
], | |
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// File location: src/App/src/Middleware/Authorization/JWTMiddleware.php | |
declare(strict_types=1); | |
namespace App\Middleware\Authorization; | |
use DateTime; | |
use DateInterval; | |
use \Firebase\JWT\JWT; | |
use Laminas\Diactoros\Response\RedirectResponse; | |
use Laminas\Diactoros\Response\TextResponse; | |
use Mezzio\Authentication\UserInterface; | |
use Mezzio\Session\SessionInterface; | |
use Psr\Http\Message\ResponseInterface; | |
use Psr\Http\Message\ServerRequestInterface; | |
use Psr\Http\Server\MiddlewareInterface; | |
use Psr\Http\Server\RequestHandlerInterface; | |
use function sprintf; | |
/** | |
* Class JWTMiddleware | |
* | |
* Requires firebase/php-jwt and mezzio-session. | |
* I need to finish up a comprehensive tutorial for | |
* authenticating with sessions in Mezzio. | |
* | |
* @package App\Middleware\Authorization | |
*/ | |
class JWTMiddleware implements MiddlewareInterface | |
{ | |
private array $config; | |
/** | |
* JWTMiddleware constructor. | |
* @param array $config | |
*/ | |
public function __construct(array $config) | |
{ | |
$this->config = $config; | |
} | |
/** | |
* Generate a JWT | |
* | |
* This implementation uses a session attribute set using mezzio-session | |
* There are likely other criteria that you can use, if you require any. | |
* | |
* @param ServerRequestInterface $request | |
* @param RequestHandlerInterface $handler | |
* @return ResponseInterface | |
* @throws \Exception | |
*/ | |
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface | |
{ | |
/** @var SessionInterface $session */ | |
$session = $request->getAttribute('session'); | |
if (! $session->has(UserInterface::class)) { | |
return new RedirectResponse('/login'); | |
} | |
return new TextResponse($this->createJWT()); | |
} | |
/** | |
* Validate the supplied JWT Token's payload | |
* | |
* @param ServerRequestInterface $request | |
* @return bool | |
*/ | |
private function hasValidToken(ServerRequestInterface $request): bool | |
{ | |
JWT::$leeway = $this->config['leeway']; | |
$payload = JWT::decode( | |
$request->getHeaderLine('Bearer'), | |
$this->config['key'], | |
$this->config['allowedAlgorithms'] | |
); | |
$timestamp = (new DateTime())->getTimestamp(); | |
return ( | |
$payload->iss !== $this->config['claim']['iss'] || | |
$payload->aud !== $this->config['claim']['aud'] || | |
$payload->nbf < $timestamp || | |
$payload->exp > $timestamp | |
); | |
} | |
/** | |
* Create a new JWT | |
* | |
* @return ServerRequestInterface | |
* @throws \Exception | |
*/ | |
private function createJWT(): string | |
{ | |
$payload = [ | |
"iss" => $this->config['claim']['iss'], | |
"aud" => $this->config['claim']['aud'], | |
"iat" => (new DateTime())->getTimestamp(), | |
"nbf" => (new DateTime())->getTimestamp(), | |
"exp" => (new DateTime())->add(new DateInterval($this->config['expiryPeriod']))->getTimestamp(), | |
]; | |
return JWT::encode($payload, $this->config['key']); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// File location: src/App/src/Middleware/Authorization/JWTMiddlewareFactory.php | |
declare(strict_types=1); | |
namespace App\Middleware\Authorization; | |
use Psr\Container\ContainerInterface; | |
use Psr\Http\Server\MiddlewareInterface; | |
class JWTMiddlewareFactory | |
{ | |
public function __invoke(ContainerInterface $container) : MiddlewareInterface | |
{ | |
$config = $container->has('config') ? $container->get('config') : []; | |
// Retrieve the configuration listed below. | |
// I'm not sure if there is, but there might be, a way to enforce the | |
// configuration element to be present. Need to have a look for that. | |
return new JWTMiddleware($config['auth']['jwt']); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@settermjd You also need to note: