Uncategorized

How to implement Facebook login with Symfony 5

Allowing your users to register and login on to your website with Facebook is pretty useful and quite standard nowadays.
Fortunately, doing this with Symfony is quite simple and we will see how to do it in a few steps.

Step 1. Installing KnpUOAuth2ClientBundle.

This bundle allows you to easily integrate multiple OAuth2 server.

Open a new terminal an type the following command.

composer require knpuniversity/oauth2-client-bundle

Step 2. Installing the Facebook Client library

KnpUOAuth2ClientBundle requires that you configure one client for each OAuth2 server you want to implement.

To install the Facebook client, open your terminal and type this command.

composer require league/oauth2-facebook

Step 3. Register your app on Facebook

To implement Facebook Login on your website, you must before register it on developers.facebook.com.

Once logged, click on the Create a new app ID and fill in the form.

Now your app is created, you should see your App dashboard. In the menu, click on Settings > General.

Copy you App ID and your secret key in your .env and .env.dist file with the keys OAUTH_FACEBOOK_ID and OAUTH_FACEBOOK_SECRET like the following.

OAUTH_FACEBOOK_ID=my_app_id
OAUTH_FACEBOOK_SECRET=my_app_secret

Step 4. Configuring the client.

Open your config/packages/knpu_oauth2_client.yaml and add the following configuration.

knpu_oauth2_client:
    clients:
        # the key "facebook" can be anything, it
        # will create a service: "knpu.oauth2.client.facebook"
        facebook:
            type: facebook
            client_id: '%env(OAUTH_FACEBOOK_ID)%'
            client_secret: '%env(OAUTH_FACEBOOK_SECRET)%'
            # the route that you're redirected to after
            redirect_route: connect_facebook_check
            redirect_params: { }
            graph_api_version: v11.0

Step 5. Creating the controller

Your controller must have two actions, the first one to start the connect process and the second is the URL where Facebook will redirect you once you are logged.

getClient('facebook')->redirect([
            'public_profile', 'email' // the scopes you want to access
        ], []);
    }

    /**
     * After going to Faceboook, you're redirected back here
     * because this is the "redirect_route" you configured
     * in config/packages/knpu_oauth2_client.yaml
     */
    #[Route('/connect/facebook/check', name: 'connect_facebook_check')]
    public function check(): RedirectResponse
    {
        return $this->redirectToRoute('your_homepage_route');
    }
}

Step 6. Creating your guard authenticator.
For now, your code allows yours user to authenticate through your OAuth server and get their user information and access token.

But now, we want to authenticate them to your application, and to do so we will use a guard authenticator instead of putting all the code in the controller.

clientRegistry = $clientRegistry;
        $this->userRepository = $userRepository;
        $this->urlGenerator = $urlGenerator;
        $this->router = $router;
        $this->entityManager = $entityManager;
    }

    public function supports(Request $request): ?bool
    {
        return 'connect_facebook_check' === $request->attributes->get('_route');
    }

    public function authenticate(Request $request): PassportInterface
    {
        $client = $this->getFacebookClient();

        $facebookUser = $this->getFacebookClient()->fetchUserFromToken($client->getAccessToken());

        return new Passport(
            new UserBadge($facebookUser->getEmail(), function ($userIdentifier) use ($request, $facebookUser) {
                $user = $this->userRepository->findOneByEmail($userIdentifier);
                if ($user) {
                    $user->setFacebookId($facebookUser->getId());
                } else {
                    // create new user
                }
                $this->entityManager->flush();

                return $user;
            }),
            new CustomCredentials(function ($credentials, User $user) {
                return $credentials->getEmail() === $user->getEmail();
            }, $facebookUser),
        );
    }

    public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface
    {
        return new UsernamePasswordToken($passport->getUser(), null, $firewallName, $passport->getUser()->getRoles());
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
            return new RedirectResponse($targetPath);
        }

        return new RedirectResponse($this->urlGenerator->generate('dashboard'));
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {
        if ($request->isXmlHttpRequest()) {
            // if AJAX login
            $response = new JsonResponse([
                'message' => strtr($exception->getMessageKey(), $exception->getMessageData()),
            ], Response::HTTP_UNAUTHORIZED);
        } else {
            // if form login
            // set authentication exception to session
            if ($request->hasSession()) {
                $request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception);
            }
            $response = new RedirectResponse($this->router->generate('app_login'));
        }

        return $response;
    }

    private function getFacebookClient()
    {
        return $this->clientRegistry->getClient('facebook');
    }
}

Now register your authenticator in the security.yaml file.

security:
    # ...
    providers:
        app_user_provider:
            entity:
                class: App\Entity\User
                property: username
    # ...
    firewalls:
        website:
            pattern: ^/
            provider: app_user_provider
            entry_point: App\Security\AuthenticationEntryPoint
            custom_authenticators:
                - App\Security\FacebookAuthenticator
            

Hope this article will help you.