Contents
- Prerequisite:
- Step 1: Install Symfony 6
- Step 2: Set Database Configuration
- Step 3: Install Packages
- Step 4: Configure The Provider
- Step 5: Create a Dashboard Controller
- Step 6: Create a User Class
- Step 7: Create a Migration File
- Step 8: Create a Login
- Step 9: Create a Registration
- Step 10: Create a Facebook Controller
- Step 11: Run the Application
In this blog, We will show you how to log in with Facebook in Symfony 6. Most of the web apps today allow users to register or log in using their Facebook, Twitter, Google, and other accounts. This is made possible by using OAuth 2.
What is Symfony? Symfony is a PHP framework to develop web applications, APIs, microservices, and web services. Symfony is one of the leading PHP frameworks for creating websites and web applications.
OAuth 2 – is a standard or protocol to implement authorization for any kind of software like desktop applications, mobile applications, and web applications.
Auth0 – is a software product (cloud and on-prem), that implements the OAuth2 protocol. You can use Auth0 to simplify your authentication and authorization requirements.
Prerequisite:
- Composer
- Symfony CLI
- MySQL
- PHP >= 8.0.2
Step 1: Install Symfony 6
First, select a folder in that you want Symfony to be installed then execute this command on Terminal or CMD to install:
Install via composer:
composer create-project symfony/website-skeleton symfony-6-facebook-login
Install via Symfony CLI:
symfony new symfony-6-facebook-login --full
Step 2: Set Database Configuration
After installing, open the .env file and set the database configuration. We will be using MySQL in this tutorial. Uncomment the DATABASE_URL variable for MySQL and updates its configs. Make sure you commented out the other DATABASE_URL variables.
.env
# In all environments, the following files are loaded if they exist,
# the latter taking precedence over the former:
#
# * .env contains default values for the environment variables needed by the app
# * .env.local uncommitted file with local overrides
# * .env.$APP_ENV committed environment-specific defaults
# * .env.$APP_ENV.local uncommitted environment-specific overrides
#
# Real environment variables win over .env files.
#
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
#
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=37febf852b869d38be2030babb187e25
###< symfony/framework-bundle ###
###> symfony/mailer ###
# MAILER_DSN=smtp://localhost
###< symfony/mailer ###
###> doctrine/doctrine-bundle ###
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
#
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
DATABASE_URL="mysql://db_user:db_password@127.0.0.1:3306/db_name?serverVersion=5.7"
# DATABASE_URL="postgresql://db_user:db_password@127.0.0.1:5432/db_name?serverVersion=13&charset=utf8"
###< doctrine/doctrine-bundle ###
After configuring the database, execute this command to create the database:
php bin/console doctrine:database:create
Step 3: Install Packages
We will now install the packages that will do the Facebook login. install these packages – knpuniversity/oauth2-client-bundle and league/oauth2-facebook.
composer require knpuniversity/oauth2-client-bundle
composer require league/oauth2-facebook
Step 4: Configure The Provider
After successfully installing the packages. we will now configure the provider. In this tutorial here is the configuration for Facebook.
config\packages\knpu_oauth2_client.yaml
knpu_oauth2_client:
clients:
# the key "facebook_main" can be anything, it
# will create a service: "knpu.oauth2.client.facebook_main"
facebook_main:
# this will be one of the supported types
type: facebook
client_id: '%env(OAUTH_FACEBOOK_ID)%'
client_secret: '%env(OAUTH_FACEBOOK_SECRET)%'
# the route that you're redirected to after
# see the controller example below
redirect_route: connect_facebook_check
redirect_params: {}
graph_api_version: v2.12
Then add the OAUTH_FACEBOOK_ID and OAUTH_FACEBOOK_SECRET on the env file. You can get these by registering your app on developers.facebook.com
.env
OAUTH_FACEBOOK_ID=fb_id
OAUTH_FACEBOOK_SECRET=fb_secret
Step 5: Create a Dashboard Controller
After setting up the database, we will then create a controller, this controller will be used by the authenticated user.
To create a controller execute this command:
php bin/console make:controller Dashboard
After executing the command, open this file ‘src\Controller\DashboardController.php’, and add this code:
src\Controller\DashboardController.php
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
class DashboardController extends AbstractController
{
#[Route('/dashboard', name: 'dashboard')]
public function index(): Response
{
$this->denyAccessUnlessGranted('IS_AUTHENTICATED_FULLY');
return $this->render('dashboard/index.html.twig', [
'controller_name' => 'DashboardController',
]);
}
}
let’s update the twig file.
templates\dashboard\index.html.twig
{% extends 'base.html.twig' %}
{% block title %}Hello DashboardController!{% endblock %}
{% block body %}
<style>
.example-wrapper { margin: 1em auto; max-width: 800px; width: 95%; font: 18px/1.5 sans-serif; }
.example-wrapper code { background: #F5F5F5; padding: 2px 6px; }
</style>
<div class="example-wrapper">
{% if app.user %}
<div class="mb-3">
You are logged in as {{ app.user.userIdentifier }}, <a href="{{ path('app_logout') }}">Logout</a>
</div>
{% endif %}
<h1>Hello {{ controller_name }}! ✅</h1>
This friendly message is coming from:
<ul>
<li>Your controller at <code><a href="{{ 'C:/Users/STH ROCKS/Desktop/BLOG SOURCE CODE/SYMFONY 6/symfony-6-login-register-facebook/src/Controller/DashboardController.php'|file_link(0) }}">src/Controller/DashboardController.php</a></code></li>
<li>Your template at <code><a href="{{ 'C:/Users/STH ROCKS/Desktop/BLOG SOURCE CODE/SYMFONY 6/symfony-6-login-register-facebook/templates/dashboard/index.html.twig'|file_link(0) }}">templates/dashboard/index.html.twig</a></code></li>
</ul>
</div>
{% endblock %}
Step 6: Create a User Class
We will then create a user class, by using the make:user command – this command will create a User class for security and it will automatically update the security.yaml.
Follow these steps:
php bin/console make:user
The name of the security user class (e.g. User) [User]:
>
Do you want to store user data in the database (via Doctrine)? (yes/no) [yes]:
>
Enter a property name that will be the unique "display" name for the user (e.g. email, username, uuid) [email]:
>
Will this app need to hash/check user passwords? Choose No if passwords are not needed or will be checked/hashed by some other system (e.g. a single sign-on server).
Does this app need to hash/check user passwords? (yes/no) [yes]:
>
created: src/Entity/User.php
created: src/Repository/UserRepository.php
updated: src/Entity/User.php
updated: config/packages/security.yaml
Success!
Next Steps:
- Review your new App\Entity\User class.
- Use make:entity to add more fields to your User entity and then run make:migration.
- Create a way to authenticate! See https://symfony.com/doc/current/security.html
Step 7: Create a Migration File
Then we will create a migration file and then migrate it:
Execute this command to create a migration file:
php bin/console make:migration
Then execute this command to run the migration the file:
php bin/console doctrine:migrations:migrate
Step 8: Create a Login
To create a login on Symfony 6, we can use the make:auth command – this command can provide an empty authenticator or a full login form authentication process depending on what you have chosen.
Execute this command and follow the steps below:
php bin/console make:auth
What style of authentication do you want? [Empty authenticator]:
[0] Empty authenticator
[1] Login form authenticator
> 1
1
The class name of the authenticator to create (e.g. AppCustomAuthenticator):
> AppCustomAuthenticator
Choose a name for the controller class (e.g. SecurityController) [SecurityController]:
>
Do you want to generate a '/logout' URL? (yes/no) [yes]:
>
created: src/Security/AppCustomAuthenticator.php
updated: config/packages/security.yaml
created: src/Controller/SecurityController.php
created: templates/security/login.html.twig
Success!
Next:
- Customize your new authenticator.
- Finish the redirect "TODO" in the App\Security\AppCustomAuthenticator::onAuthenticationSuccess() method.
- Check the user's password in App\Security\AppCustomAuthenticator::checkCredentials().
- Review & adapt the login template: templates/security/login.html.twig.
After following the steps above, open the file ‘src\Security\AppCustomAuthenticator.php’ and update a part of the code:
src\Security\AppCustomAuthenticator.php
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
if ($targetPath = $this->getTargetPath($request->getSession(), $firewallName)) {
return new RedirectResponse($targetPath);
}
// For example:
return new RedirectResponse($this->urlGenerator->generate('dashboard'));
// throw new \Exception('TODO: provide a valid redirect inside '.__FILE__);
}
We will update the SecurityController.php.
src\Controller\SecurityController.php
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
class SecurityController extends AbstractController
{
#[Route(path: '/', name: 'app_login')]
public function login(AuthenticationUtils $authenticationUtils): Response
{
if ($this->getUser()) {
return $this->redirectToRoute('dashboard');
}
$error = $authenticationUtils->getLastAuthenticationError();
$lastUsername = $authenticationUtils->getLastUsername();
return $this->render('security/login.html.twig', ['last_username' => $lastUsername, 'error' => $error]);
}
#[Route(path: '/logout', name: 'app_logout')]
public function logout(): void
{
throw new \LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
}
}
Let’s update the twig file to add the Facebook login.
templates\security\login.html.twig
{% extends 'base.html.twig' %}
{% block title %}Log in!{% endblock %}
{% block body %}
<form method="post">
{% if error %}
<div class="alert alert-danger">{{ error.messageKey|trans(error.messageData, 'security') }}</div>
{% endif %}
{% if app.user %}
<div class="mb-3">
You are logged in as {{ app.user.userIdentifier }}, <a href="{{ path('app_logout') }}">Logout</a>
</div>
{% endif %}
<h1 class="h3 mb-3 font-weight-normal">Please sign in</h1>
<label for="inputEmail">Email</label>
<input type="email" value="{{ last_username }}" name="email" id="inputEmail" class="form-control" autocomplete="email" required autofocus>
<label for="inputPassword">Password</label>
<input type="password" name="password" id="inputPassword" class="form-control" autocomplete="current-password" required>
<input type="hidden" name="_csrf_token"
value="{{ csrf_token('authenticate') }}"
>
{#
Uncomment this section and add a remember_me option below your firewall to activate remember me functionality.
See https://symfony.com/doc/current/security/remember_me.html
<div class="checkbox mb-3">
<label>
<input type="checkbox" name="_remember_me"> Remember me
</label>
</div>
#}
<button class="btn btn-lg btn-primary" type="submit">
Sign in
</button>
<a href="{{ path('connect_facebook_start') }}">Login Using Facebook</a>
</form>
{% endblock %}
Step 9: Create a Registration
After creating the Login we will then create the Registration. We can use the make:registration command.
Execute this command and follow the steps below:
php bin/console make:registration
Creating a registration form for App\Entity\User
Do you want to add a @UniqueEntity validation annotation on your User class to make sure duplicate accounts aren't created? (yes/no) [yes]:
>
Do you want to send an email to verify the user's email address after registration? (yes/no) [yes]:
> no
Do you want to automatically authenticate the user after registration? (yes/no) [yes]:
>
updated: src/Entity/User.php
created: src/Form/RegistrationFormType.php
created: src/Controller/RegistrationController.php
created: templates/registration/register.html.twig
Success!
Next:
Make any changes you need to the form, controller & template.
Then open your browser, go to "/register" and enjoy your new form!
Step 10: Create a Facebook Controller
Now we will create the controller that will handle the Facebook login.
To create a controller execute this command:
php bin/console make:controller Facebook
After executing the command, open this file ‘src\Controller\FacebookController.php’, and add this code:
<?php
namespace App\Controller;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use App\Entity\User;
use Symfony\Component\PasswordHasher\Hasher\UserPasswordHasherInterface;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Component\Security\Http\Authentication\UserAuthenticatorInterface;
use App\Security\AppCustomAuthenticator;
class FacebookController extends AbstractController
{
#[Route('/connect/facebook', name: 'connect_facebook_start')]
public function connectAction(ClientRegistry $clientRegistry)
{
if ($this->getUser()) {
return $this->redirectToRoute('dashboard');
}
return $clientRegistry
->getClient('facebook_main')
->redirect([],[
'public_profile', 'email'
]);
}
#[Route('/connect/facebook/check', name: 'connect_facebook_check')]
public function connectCheckAction(
Request $request,
ClientRegistry $clientRegistry,
UserPasswordHasherInterface $userPasswordHasher,
EntityManagerInterface $entityManager,
UserAuthenticatorInterface $userAuthenticator,
AppCustomAuthenticator $authenticator)
{
if ($this->getUser()) {
return $this->redirectToRoute('dashboard');
}
$client = $clientRegistry->getClient('facebook_main');
try {
$facebookUser = $client->fetchUser();
// check if email exist
$existingUser = $entityManager->getRepository(User::class)
->findOneBy(['email' => $facebookUser->getEmail()]);
if($existingUser){
return $userAuthenticator->authenticateUser(
$existingUser,
$authenticator,
$request
);
}
$user = new User();
$user->setPassword(
$userPasswordHasher->hashPassword(
$user,
$facebookUser->getId()
)
);
$user->setEmail($facebookUser->getEmail());
$entityManager->persist($user);
$entityManager->flush();
return $userAuthenticator->authenticateUser(
$user,
$authenticator,
$request
);
} catch (IdentityProviderException $e) {
var_dump($e->getMessage()); die;
}
}
}
Step 11: Run the Application
After finishing the steps above, you can now run your application by executing the command below:
symfony server:start
After successfully running your app, open these URL’s in your browser:
Login:
https://localhost:8000/
Register:
https://localhost:8000/register
Dashboard(If authenticated):
https://localhost:8000/dashboard