tarlepp/symfony-flex-backend

View on GitHub
src/Security/Authenticator/ApiKeyAuthenticator.php

Summary

Maintainability
A
0 mins
Test Coverage
A
100%
<?php
declare(strict_types = 1);
/**
 * /src/Security/Authenticator/ApiKeyAuthenticator.php
 *
 * @author TLe, Tarmo Leppänen <tarmo.leppanen@pinja.com>
 */

namespace App\Security\Authenticator;

use App\Security\Provider\ApiKeyUserProvider;
use Override;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Core\Exception\UserNotFoundException;
use Symfony\Component\Security\Http\Authenticator\AbstractAuthenticator;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use function preg_match;

/**
 * @package App\Security\Authenticator
 * @author TLe, Tarmo Leppänen <tarmo.leppanen@pinja.com>
 */
class ApiKeyAuthenticator extends AbstractAuthenticator
{
    public function __construct(
        private readonly ApiKeyUserProvider $apiKeyUserProvider,
    ) {
    }

    #[Override]
    public function supports(Request $request): ?bool
    {
        return $this->getToken($request) !== '';
    }

    #[Override]
    public function authenticate(Request $request): Passport
    {
        $token = $this->getToken($request);
        $apiKey = $this->apiKeyUserProvider->getApiKeyForToken($token);

        if ($apiKey === null) {
            throw new UserNotFoundException('API key not found');
        }

        return new SelfValidatingPassport(new UserBadge($token));
    }

    #[Override]
    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        return null;
    }

    #[Override]
    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): Response
    {
        $data = [
            'code' => 401,
            'message' => 'Invalid API key',
        ];

        return new JsonResponse($data, Response::HTTP_UNAUTHORIZED);
    }

    private function getToken(Request $request): string
    {
        preg_match('#^ApiKey (\w+)$#', $request->headers->get('Authorization', ''), $matches);

        return $matches[1] ?? '';
    }
}