Home > Software design >  Symfony JSON Login - Session vs Token
Symfony JSON Login - Session vs Token

Time:08-24

I'm learning how to use the Symfony Security Bundle with a JSON-Login.

Therefore I've been following the official guide: https://symfony.com/doc/current/security.html#json-login

Interestingly, after getting authenticated, I do not need to send the generated token at all. It rather seems to remember me by Session-Cookie.

$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');

As a beginner, I've got following questions:

  • Is this a reasonable behavior, given you are using a REST API to authenticate?
  • If I would use a token, what would be an acceptable way of creating it? Can I just provide a UID?

CodePudding user response:

For token authentication, you can create a custom authenticator. Otherwise Symfony uses session authentication. It depends on how the frontend looks like. Do you have a way to save and reuse the session on the frontend side? Then session authentication is possible. If this is not possible, you should use token-based authentication.

For the creation of the token you can create a route for the registration. This should be available for anonymous users. Here the credentials (e.g. e-mail and password) are checked. Then you create a token (preferably UUID) and save it in the user table. Finally you send the token back in your response. For the other requests you have to send this token in the header. Symfony then automatically takes over the authentication.

According to the documentation you first create an authenticator class. (https://symfony.com/doc/current/security/custom_authenticator.html)

// src/Security/ApiKeyAuthenticator.php
namespace App\Security;

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\CustomUserMessageAuthenticationException;
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;

class ApiKeyAuthenticator extends AbstractAuthenticator
{
    /**
     * Called on every request to decide if this authenticator should be
     * used for the request. Returning `false` will cause this authenticator
     * to be skipped.
     */
    public function supports(Request $request): ?bool
    {
        return $request->headers->has('X-AUTH-TOKEN');
    }

    public function authenticate(Request $request): Passport
    {
        $apiToken = $request->headers->get('X-AUTH-TOKEN');
        if (null === $apiToken) {
            // The token header was empty, authentication fails with HTTP Status
            // Code 401 "Unauthorized"
            throw new CustomUserMessageAuthenticationException('No API token provided');
        }

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

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        // on success, let the request continue
        return null;
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {
        $data = [
            // you may want to customize or obfuscate the message first
            'message' => strtr($exception->getMessageKey(), $exception->getMessageData())

            // or to translate this message
            // $this->translator->trans($exception->getMessageKey(), $exception->getMessageData())
        ];

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

Then you have to register it in the configuration.

# config/packages/security.yaml
security:

    # ...
    firewalls:
        main:
            custom_authenticators:
                - App\Security\ApiKeyAuthenticator
  • Related