427 words
2 minutes
Authentication with Facebook in Symfony 6

In a previous article, I already covered this topic using Google authentication as an example. Today, we’ll do the same with Facebook. (The most complicated part is often obtaining the Facebook API keys.)


One of the benefits of logging in using a Facebook account is that it spares the user from creating yet another password.

Creating the Symfony Project#

As usual, we’ll start from scratch and create the project:

symfony new sffacebook

Next, let’s add all the required libraries:

composer req twig
composer req --dev symfony/maker-bundle
composer req security
composer req orm
composer req --dev debug

And specifically those needed for using Facebook for authentication:

composer require knpuniversity/oauth2-client-bundle
composer require league/oauth2-facebook

Facebook Configuration#

First, obtain your Facebook keys. Log in to the Facebook Developer Portal, go to “My Apps,” and click “Create App.”

Choose “None” as the app type:

App Type Selection

Enter your app’s name (e.g., SymfonyAuth) without using reserved words like “Facebook” or “FB.”

Next, add the “Facebook Login” product:

Adding the Facebook Login Product

In the left menu, under “Facebook Login,” click “Settings” and configure the valid OAuth redirect URIs (e.g., https://your-domain/connect/facebook/check):

Configuring Redirect URIs

Finally, go to “Settings -> General” and retrieve your app ID and secret. Add them to your .env.local file:

OAUTH_FACEBOOK_CLIENT_ID=app_id
OAUTH_FACEBOOK_CLIENT_SECRET=app_secret

Creating the User Entity#

Use the MakerBundle to create the User entity:

bin/console make:entity

Add the necessary columns and migrate the database:

bin/console make:migration
bin/console doctrine:migration:migrate

Configuring Authentication#

In the config/packages/knpu_oauth2_client.yaml file:

knpu_oauth2_client:
    clients:
        facebook:
            type: facebook
            client_id: '%env(OAUTH_FACEBOOK_CLIENT_ID)%'
            client_secret: '%env(OAUTH_FACEBOOK_CLIENT_SECRET)%'
            redirect_route: connect_facebook_check
            graph_api_version: v2.12

Creating a Controller#

Create a controller to handle login/logout and Facebook authentication:

<?php

namespace App\Controller;

use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

class FacebookController extends AbstractController
{
    #[Route('/connect/facebook', name: 'connect_facebook')]
    public function connectAction(ClientRegistry $clientRegistry): RedirectResponse
    {
        return $clientRegistry->getClient('facebook')->redirect(['public_profile', 'email'], []);
    }

    #[Route('/connect/facebook/check', name: 'connect_facebook_check')]
    public function connectCheckAction(Request $request)
    {
        // Handle post-authentication logic
    }
}

Add a login button to your Twig template (facebook/index.html.twig):

<a href="{{ path('connect_facebook') }}">
    <img src="/facebooklogo.png" alt="Log in with Facebook">
</a>

Setting Up a GuardAuthenticator#

Create a GuardAuthenticator to manage user authentication:

<?php
namespace App\Security;

use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use KnpU\OAuth2ClientBundle\Security\Authenticator\OAuth2Authenticator;
use League\OAuth2\Client\Provider\FacebookUser;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;

class FacebookAuthenticator extends OAuth2Authenticator
{
    public function __construct(
        private ClientRegistry $clientRegistry,
        private EntityManagerInterface $entityManager,
        private RouterInterface $router
    ) {}

    public function authenticate(Request $request): Passport
    {
        $client = $this->clientRegistry->getClient('facebook');
        $accessToken = $this->fetchAccessToken($client);

        return new SelfValidatingPassport(
            new UserBadge($accessToken->getToken(), function () use ($client, $accessToken) {
                $facebookUser = $client->fetchUserFromToken($accessToken);
                $email = $facebookUser->getEmail();

                $existingUser = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $email]);
                if (!$existingUser) {
                    $existingUser = new User();
                    $existingUser->setEmail($email);
                    $this->entityManager->persist($existingUser);
                }
                $this->entityManager->flush();

                return $existingUser;
            })
        );
    }
}

Configure security.yaml to use the GuardAuthenticator:

firewalls:
    main:
        custom_authenticators:
            - App\Security\FacebookAuthenticator

Conclusion#

You can now log in to your site via Facebook. To log out, visit /logout.

The complete code is available on GitHub: https://github.com/gponty/sffacebook