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;
    }
}

 

RelatedWhat 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.