Skip to content

Instantly share code, notes, and snippets.

@vincentchalamon
Created August 27, 2019 10:22
Show Gist options
  • Save vincentchalamon/b68ae60d34adf91c332e81ed4f0b879d to your computer and use it in GitHub Desktop.
Save vincentchalamon/b68ae60d34adf91c332e81ed4f0b879d to your computer and use it in GitHub Desktop.
<?php
declare(strict_types=1);
namespace App\Mercure\EventSubscriber;
use App\Mercure\JwtProvider;
use Fig\Link\Link;
use Psr\Link\LinkProviderInterface;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\FilterResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
/**
* @author Vincent Chalamon <vincent@les-tilleuls.coop>
*/
final class AuthorizationEventSubscriber implements EventSubscriberInterface
{
private $jwtProvider;
public function __construct(JwtProvider $jwtProvider)
{
$this->jwtProvider = $jwtProvider;
}
public static function getSubscribedEvents(): array
{
return [
KernelEvents::RESPONSE => 'onKernelResponse',
];
}
public function onKernelResponse(FilterResponseEvent $event): void
{
$attributes = $event->getRequest()->attributes;
if (!$attributes->has('_links') || !$attributes->get('_links') instanceof LinkProviderInterface) {
return;
}
foreach ($attributes->get('_links')->getLinks() as $link) {
/** @var Link $link */
if (\in_array('mercure', $link->getRels(), true)) {
// Add Mercure cookie with JWT only if Mercure hub url is present in Links response header
$event->getResponse()->headers->set(
'set-cookie',
sprintf('mercureAuthorization=%s; path=/hub; secure; httponly; SameSite=strict', ($this->jwtProvider)())
);
}
}
}
}
@vincentchalamon
Copy link
Author

vincentchalamon commented Oct 1, 2019

declare(strict_types=1);

namespace App\Mercure;

use App\Entity\Core\User;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Hmac\Sha256;
use Lcobucci\JWT\Signer\Key;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;

/**
 * @author Vincent Chalamon <vincent@les-tilleuls.coop>
 */
final class JwtProvider
{
    private $tokenStorage;
    private $secret;
    private $subscribeUrl;

    public function __construct(TokenStorageInterface $tokenStorage, string $secret, string $subscribeUrl)
    {
        $this->tokenStorage = $tokenStorage;
        $this->secret = $secret;
        $this->subscribeUrl = $subscribeUrl;
    }

    public function __invoke(): ?string
    {
        if (!($token = $this->tokenStorage->getToken()) || !($user = $token->getUser()) || !$user instanceof User) {
            return null;
        }

        return (new Builder())
            ->withClaim('mercure', ['subscribe' => [$user->getId()]])
            ->getToken(new Sha256(), new Key($this->secret))->__toString();
    }
}

@vincentchalamon
Copy link
Author

App\Mercure\JwtProvider:
    arguments:
        $secret: '%env(MERCURE_JWT_KEY)%'
        $subscribeUrl: '%env(MERCURE_SUBSCRIBE_URL)%'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment