app/GraphQL/Security/Authenticator/PasetoAuthenticator.php line 17

Open in your IDE?
  1. <?php
  2. namespace Sq\GraphQL\Security\Authenticator;
  3. use Psr\Log\LoggerInterface;
  4. use Sq\GraphQL\Security\TokenManager;
  5. use Symfony\Component\HttpFoundation\Request;
  6. use Symfony\Component\HttpFoundation\RequestStack;
  7. use Symfony\Component\HttpFoundation\Response;
  8. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  9. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  10. use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
  11. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
  12. use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
  13. use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
  14. class PasetoAuthenticator extends AbstractAuthenticator
  15. {
  16.     use ImpersonationTrait;
  17.     protected const AUTH_HEADER 'Authorization';
  18.     protected const IMPERSONATE_HEADER 'Impersonate-Uid';
  19.     protected const BEARER_REGEX '/^(?:\s+)?Bearer\s/';
  20.     public function __construct(
  21.         protected TokenManager $tokenManager,
  22.         protected LoggerInterface $logger,
  23.         protected RequestStack $requestStack,
  24.     ) {
  25.     }
  26.     public function createToken(Passport $passportstring $firewallName): TokenInterface
  27.     {
  28.         $token parent::createToken($passport$firewallName);
  29.         $impersonateUid $this->requestStack->getMainRequest()->headers->get(static::IMPERSONATE_HEADER);
  30.         if ($impersonateUid)
  31.         {
  32.             $token $this->createImpersonationToken($token, (int) $impersonateUid$firewallName);
  33.         }
  34.         return $token;
  35.     }
  36.     public function supports(Request $request): bool
  37.     {
  38.         return $request->headers->has(static::AUTH_HEADER)
  39.             && preg_match(static::BEARER_REGEX$request->headers->get(static::AUTH_HEADER));
  40.     }
  41.     public function authenticate(Request $request): Passport
  42.     {
  43.         $header $request->headers->get(static::AUTH_HEADER);
  44.         $token trim(preg_replace(static::BEARER_REGEX''$header));
  45.         return new SelfValidatingPassport(new UserBadge((string) $this->tokenManager->getAccessTokenOwnerId($token)));
  46.     }
  47.     public function onAuthenticationFailure(Request $requestAuthenticationException $exception): ?Response
  48.     {
  49.         $this->logger && $this->logger->debug('Authentication failure', [
  50.             'exception' => $exception,
  51.             'guard' => __CLASS__,
  52.         ]);
  53.         // Normally we would throw an exception or return a redirect response back to the login page, but...
  54.         // Similar to onAuthenticationSuccess(), continue execution flow but with no authenticated user. This is because
  55.         // this particular guard is for GraphQL and we want all errors (including auth errors resulting from no-one logged
  56.         // in) to be handled by the GraphQL controller so it can return a properly formatted GraphQL error response.
  57.         return null;
  58.     }
  59.     public function onAuthenticationSuccess(Request $requestTokenInterface $token$providerKey): ?Response
  60.     {
  61.         // As this is authenticating for an API and authenticated on every request, just continue the request onto the
  62.         // appropriate controller instead of returning a response here (for a successful login page or redirect to last
  63.         // page user visited, etc).
  64.         return null;
  65.     }
  66. }