Since pretty much any potential user of an app has a Facebook or a Google account, it’s crucial to have a login or registration service using these social networks. Luckily, HWIOAuthBundle provides the necessary tools to accomplish this. So here’s an easy and straightforward way to integrate HWIOAuth in our app alongside FOSUserBundle:
Symfony2 Facebook and Google Login: The Easy Way
1. Configure HWIOauthBundle
Assuming that you’ve already installed and configured FOSUserBundle, we now need to add HWIOAuthBundle in our application. As mentioned in their setup page, we simply have to:
composer require hwi/oauth-bundle
Then we should enable the bundle in the kernel:
// app/AppKernel.php public function registerBundles() { $bundles = array( // ... new HWI\Bundle\OAuthBundle\HWIOAuthBundle(), ); }
and then we can import the social routes:
# app/config/routing.yml hwi_oauth_redirect: resource: "@HWIOAuthBundle/Resources/config/routing/redirect.xml" prefix: /connect hwi_oauth_login: resource: "@HWIOAuthBundle/Resources/config/routing/login.xml" prefix: /login
Once we have these setup, we can start configuring the security details in security.yml
:
firewalls: main: pattern: ^/ oauth: failure_path: your_path login_path: your_path check_path: /connect_check provider: fos_userbundle resource_owners: facebook: "/login/check-facebook" google: "/login/check-google" oauth_user_provider: service: app.provider.oauth
And then we can finally add Facebook and Google into HWIOAuth’s configuration in config.yml
:
hwi_oauth: # name of the firewall in which this bundle is active, this setting MUST be set firewall_name: main connect: account_connector: app.provider.oauth resource_owners: facebook: type: facebook client_id: %facebook_client_id% client_secret: %facebook_client_secret% scope: "email, public_profile" infos_url: "https://graph.facebook.com/me?fields=id,name,email,picture.type(large)" paths: email: email options: display: page google: type: google client_id: %google_client_id% client_secret: %google_client_secret% scope: "https://www.googleapis.com/auth/userinfo.email https://www.googleapis.com/auth/userinfo.profile" paths: email: email
2. Build our own user provider by extending HWIOAuth’s FOSUBUserProvider
As you’ve probably noticed, we used app.provider.oauth
in both security.yml
and config.yml
. So we need to define that service in services.yml
:
app.provider.oauth: class: AppBundle\Security\Core\User\OAuthUserProvider arguments: [@fos_user.user_manager,{facebook: facebookID, google: googleID}]
And then build it in our AppBundle:
<?php namespace AppBundle\Security\Core\User; use HWI\Bundle\OAuthBundle\OAuth\Response\UserResponseInterface; use HWI\Bundle\OAuthBundle\Security\Core\User\FOSUBUserProvider as BaseClass; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\User\UserChecker; use Symfony\Component\Security\Core\User\UserInterface; /** * Class OAuthUserProvider * @package AppBundle\Security\Core\User */ class OAuthUserProvider extends BaseClass { /** * {@inheritdoc} */ public function loadUserByOAuthUserResponse(UserResponseInterface $response) { $socialID = $response->getUsername(); $user = $this->userManager->findUserBy(array($this->getProperty($response)=>$socialID)); $email = $response->getEmail(); //check if the user already has the corresponding social account if (null === $user) { //check if the user has a normal account $user = $this->userManager->findUserByEmail($email); if (null === $user || !$user instanceof UserInterface) { //if the user does not have a normal account, set it up: $user = $this->userManager->createUser(); $user->setEmail($email); $user->setPlainPassword(md5(uniqid())); $user->setEnabled(true); } //then set its corresponding social id $service = $response->getResourceOwner()->getName(); switch ($service) { case 'google': $user->setGoogleID($socialID); break; case 'facebook': $user->setFacebookID($socialID); break; } $this->userManager->updateUser($user); } else { //and then login the user $checker = new UserChecker(); $checker->checkPreAuth($user); } return $user; } }
Related: What Nobody Tells You When You’re a Junior Developer
3. Override the User Model
In our user provider defined above we modified two attributes that do not exist in FOSUser’s User model: $facebookId
and $googleId
. So we need to override the User model and add them.
namespace AppBundle\Entity; use FOS\UserBundle\Model\User as BaseUser; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity(repositoryClass="AppBundle\Entity\UserRepository") * @ORM\Table(name="fos_user") */ class User extends BaseUser { /** * @ORM\Id * @ORM\Column(type="integer") * @ORM\GeneratedValue(strategy="AUTO") */ protected $id; /** * @var string * * @ORM\Column(name="facebook_id", type="string", nullable=true) */ private $facebookID; /** * @var string * * @ORM\Column(name="google_id", type="string", nullable=true) */ private $googleID; // ... }
Don’t forget to update your database and then you can move forward to the next step.
4. Add Facebook and Google to our login and register pages
Now we’re all set to update our Twig files with HWIOauth’s paths. Since we’re using FOSUser, we’ve overridden their register.html.twig
and login.html.twig
files and then added the social links:
{# ... #} <a href="{{ path('hwi_oauth_service_redirect', {'service': 'facebook' }) }}"> <span>Facebook</span> </a> <a href="{{ path('hwi_oauth_service_redirect', {'service': 'google' }) }}"> <span>Google</span> </a> {# ... #}
And there you have it: a fully functional Facebook and Google login and signup system. Now we can go to Facebook Developers and Google Developers Console, create our apps and add our client_id
and client_secret
in config.yml
. Have fun!
If you have a different take on this process and can make it even easier, please let us know in the comment section below.
13 Comments
Comments are closed.
Hello. I’m using Symfony 3. And after success authorize via google and redirect to my site I got this error: No route found for “GET /login/check-google”. How can I fix it?
Hi Artem! Have you cleared your cache?
One other problem I found is that we need to use firewall_names: [main] instead of firewall_name: main in config.yml
Yes Dragos Holban, I cleared cache and using firewall_names: [main] in my config.yml file. But the error still same.
Also I heard that problems can be with using “pattern” in security.yml. So, anyway I can’t resolve my error.(((
Ok, I will try to dig further to see if I find out what is wrong. Unfortunately this post was written for Symfony 2 so there are probably some other breaking changes. I’ll let you know if I find something.
Is your code available somehow? It will be easier for me to debug having the code and not trying to guess the problem 🙂
Unfortunately I can not give the code. But I also tried to integrate https://github.com/hwi/HWIOAuthBundle/. Using their documentation for Symfony3 and the result was the same. The same mistake. Thank you. I will follow the comments or you can write me an e-mail artemstarchkov@gmail.com
You need to add the route(s) for the resource_owners to your app/config/routing.yml
google_login:
path: /login/check-google
see: https://github.com/hwi/HWIOAuthBundle/blob/master/Resources/doc/3-configuring_the_security_layer.md
Thanks for your answer. But I’m added this to “routing.yml”. I did all steps like it was wrote in HWIOAuthBundle documentation and still have problem.
Do you try integrate HWIOAuthBundle to your project?
Yes Dragos Holban, I cleared cache and using firewall_names: [main] in my config.yml file. But the error still same.
Hello Dragos Holban. How are you? What news about integrate HWIOAuthBundle into symfony 3 project with FOSUserBundle ?
[…] Related: Symfony2 Facebook and Google Login: The Easy Way […]