Search code examples
symfonyauthenticationsymfony4

Simple api auth with static key


I've got my project API secured by symfony security firewalls, got user providers and more. Now I need few public routes secured only with single token, I mean single random 32 char string and not need user provider, jwt token etc, just check this static string matches mine or not and respond. Is there better way in symfony(4) than using kernel events on every request event?


Solution

  • This is a class I've used for another project where all routes should be secured by a URL token:

    <?php
    
    namespace App\AccessControl;
    
    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    use Symfony\Component\HttpKernel\Event\ControllerEvent;
    use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
    use Symfony\Component\HttpKernel\KernelEvents;
    
    class AccessControlSubscriber implements EventSubscriberInterface
    {
    
        private string $token;
    
        public function __construct(string $token)
        {
            $this->token = $token;
        }
    
        public static function getSubscribedEvents(): array
        {
            return [
                KernelEvents::CONTROLLER => 'onKernelController',
            ];
        }
    
        public function onKernelController(ControllerEvent $event): void
        {
            $controller = $event->getController();
    
            if (!is_array($controller)) {
                return;
            }
    
            $request = $event->getRequest();
    
            if (0 === strpos($request->getPathInfo(), '/_profiler') || 0 === strpos($request->getPathInfo(), '/_fragment')) {
                return;
            }
    
            $token = $request->query->get('token');
    
            if ($this->token !== $token || $this->token === '') {
                throw new AccessDeniedHttpException('This action needs a valid token!');
            }
        }
    }
    

    It hooks into all kernel events where a controller is used, right before the controller's arguments are resolved and the controller action itself is called. The profiler routes are excluded, such that you can still use it.


    If you want to use this only for some controllers, you could check for specific classes set in the $controller array, just like I did it for the routes of the profiler toolbar