{"id":1753,"date":"2015-11-13T11:16:36","date_gmt":"2015-11-13T11:16:36","guid":{"rendered":"https:\/\/intelligentbee.com\/blog\/?p=1753"},"modified":"2024-11-01T11:29:28","modified_gmt":"2024-11-01T11:29:28","slug":"symfony2-facebook-google-login","status":"publish","type":"post","link":"https:\/\/intelligentbee.com\/blog\/symfony2-facebook-google-login\/","title":{"rendered":"Symfony2 Facebook and Google Login: The Easy Way"},"content":{"rendered":"<p>Since pretty much any potential user of an\u00a0app has a Facebook or a Google account, it&#8217;s crucial to have\u00a0a login or registration service using these social networks. Luckily, <span style=\"color: #ff6600;\"><a style=\"color: #ff6600;\" href=\"https:\/\/github.com\/hwi\/HWIOAuthBundle\" target=\"_blank\" rel=\"noopener\">HWIOAuthBundle<\/a><\/span> provides the necessary tools to accomplish this. So\u00a0here&#8217;s an easy and straightforward way to integrate HWIOAuth in our app alongside FOSUserBundle:<\/p>\n<p>&nbsp;<\/p>\n<h2>Symfony2 Facebook and Google Login: The Easy Way<\/h2>\n<p>&nbsp;<\/p>\n<h3>1. Configure HWIOauthBundle<\/h3>\n<p>Assuming that you&#8217;ve already installed and configured <span style=\"color: #ff6600;\"><a style=\"color: #ff6600;\" href=\"https:\/\/github.com\/FriendsOfSymfony\/FOSUserBundle\" target=\"_blank\" rel=\"noopener\">FOSUserBundle<\/a><\/span>, we\u00a0now need to add HWIOAuthBundle in our\u00a0application.\u00a0As mentioned in <span style=\"color: #ff6600;\">their setup page<\/span>, we\u00a0simply have to:<\/p>\n<pre class=\"toolbar:2 striped:false marking:false ranges:false nums:false nums-toggle:false wrap:true tab-convert:true whitespace-before:1 whitespace-after:1 lang:sh decode:true inline-margin:\">composer require hwi\/oauth-bundle<\/pre>\n<p>Then we should\u00a0enable the bundle in the kernel:<\/p>\n<pre class=\"toolbar:2 striped:false marking:false ranges:false nums:false nums-toggle:false wrap:true tab-convert:true whitespace-before:1 whitespace-after:1 lang:php decode:true\">\/\/ app\/AppKernel.php\r\n\r\npublic function registerBundles()\r\n{\r\n    $bundles = array(\r\n        \/\/ ...\r\n        new HWI\\Bundle\\OAuthBundle\\HWIOAuthBundle(),\r\n    );\r\n}\r\n<\/pre>\n<p><span style=\"line-height: 1.5;\">and then we can <\/span><span style=\"line-height: 1.5;\">import<\/span><span style=\"line-height: 1.5;\">\u00a0the social\u00a0routes:<\/span><\/p>\n<pre class=\"toolbar:2 striped:false marking:false ranges:false nums:false nums-toggle:false wrap:true tab-convert:true whitespace-before:1 whitespace-after:1 lang:sh decode:true\"># app\/config\/routing.yml\r\nhwi_oauth_redirect:\r\n    resource: \"@HWIOAuthBundle\/Resources\/config\/routing\/redirect.xml\"\r\n    prefix:   \/connect\r\n\r\nhwi_oauth_login:\r\n    resource: \"@HWIOAuthBundle\/Resources\/config\/routing\/login.xml\"\r\n    prefix:   \/login<\/pre>\n<p>Once we\u00a0have these setup, we\u00a0can start configuring the security details in <code>security.yml<\/code>:<\/p>\n<pre class=\"toolbar:2 show-title:false striped:false marking:false ranges:false nums:false nums-toggle:false wrap:true whitespace-before:1 whitespace-after:1 lang:sh decode:true\">firewalls:\r\n    main:\r\n        pattern: ^\/\r\n        oauth:\r\n            failure_path: your_path\r\n            login_path: your_path\r\n            check_path: \/connect_check\r\n            provider: fos_userbundle\r\n            resource_owners:\r\n                facebook: \"\/login\/check-facebook\"\r\n                google: \"\/login\/check-google\"\r\n            oauth_user_provider:\r\n                service: app.provider.oauth<\/pre>\n<p>And\u00a0then we can finally add\u00a0Facebook and Google into HWIOAuth&#8217;s configuration in <code>config.yml<\/code>:<\/p>\n<pre class=\"toolbar:2 striped:false marking:false ranges:false nums:false nums-toggle:false wrap:true tab-convert:true whitespace-before:1 whitespace-after:1 lang:sh decode:true\">hwi_oauth:\r\n    # name of the firewall in which this bundle is active, this setting MUST be set\r\n    firewall_name: main\r\n    connect:\r\n        account_connector: app.provider.oauth\r\n    resource_owners:\r\n        facebook:\r\n            type:                facebook\r\n            client_id:           %facebook_client_id%\r\n            client_secret:       %facebook_client_secret%\r\n            scope:               \"email, public_profile\"\r\n            infos_url:           \"https:\/\/graph.facebook.com\/me?fields=id,name,email,picture.type(large)\"\r\n            paths:\r\n                email: email\r\n            options:\r\n                display: page\r\n        google:\r\n            type:                google\r\n            client_id:           %google_client_id%\r\n            client_secret:       %google_client_secret%\r\n            scope:              \"https:\/\/www.googleapis.com\/auth\/userinfo.email https:\/\/www.googleapis.com\/auth\/userinfo.profile\"\r\n            paths:\r\n                email: email<\/pre>\n<p>&nbsp;<\/p>\n<h3>2. Build our\u00a0own user provider by extending HWIOAuth&#8217;s <code>FOSUBUserProvider<\/code><\/h3>\n<p>As you&#8217;ve probably noticed, we used <code>app.provider.oauth<\/code> in both <code>security.yml<\/code> and <code>config.yml<\/code>. So we need to define that service in <code>services.yml<\/code>:<\/p>\n<pre class=\"toolbar:2 striped:false marking:false ranges:false nums:false nums-toggle:false wrap:true tab-convert:true whitespace-before:1 whitespace-after:1 lang:sh decode:true\">app.provider.oauth:\r\n    class: AppBundle\\Security\\Core\\User\\OAuthUserProvider\r\n    arguments: [@fos_user.user_manager,{facebook: facebookID, google: googleID}]<\/pre>\n<p>And then build it in our AppBundle:<\/p>\n<pre class=\"toolbar:2 striped:false marking:false ranges:false nums:false nums-toggle:false wrap:true tab-convert:true whitespace-before:1 whitespace-after:1 lang:php decode:true\">&lt;?php\r\nnamespace AppBundle\\Security\\Core\\User;\r\n\r\nuse HWI\\Bundle\\OAuthBundle\\OAuth\\Response\\UserResponseInterface;\r\nuse HWI\\Bundle\\OAuthBundle\\Security\\Core\\User\\FOSUBUserProvider as BaseClass;\r\nuse Symfony\\Component\\Security\\Core\\Exception\\AuthenticationException;\r\nuse Symfony\\Component\\Security\\Core\\User\\UserChecker;\r\nuse Symfony\\Component\\Security\\Core\\User\\UserInterface;\r\n\/**\r\n * Class OAuthUserProvider\r\n * @package AppBundle\\Security\\Core\\User\r\n *\/\r\nclass OAuthUserProvider extends BaseClass\r\n{       \r\n    \/**\r\n     * {@inheritdoc}\r\n     *\/\r\n    public function loadUserByOAuthUserResponse(UserResponseInterface $response)\r\n    {\r\n        $socialID = $response-&gt;getUsername();\r\n        $user = $this-&gt;userManager-&gt;findUserBy(array($this-&gt;getProperty($response)=&gt;$socialID));\r\n        $email = $response-&gt;getEmail();\r\n        \/\/check if the user already has the corresponding social account\r\n        if (null === $user) {\r\n            \/\/check if the user has a normal account\r\n            $user = $this-&gt;userManager-&gt;findUserByEmail($email);\r\n\r\n            if (null === $user || !$user instanceof UserInterface) {\r\n                \/\/if the user does not have a normal account, set it up:\r\n                $user = $this-&gt;userManager-&gt;createUser();\r\n                $user-&gt;setEmail($email);\r\n                $user-&gt;setPlainPassword(md5(uniqid()));\r\n                $user-&gt;setEnabled(true);\r\n            }\r\n            \/\/then set its corresponding social id\r\n            $service = $response-&gt;getResourceOwner()-&gt;getName();\r\n            switch ($service) {\r\n                case 'google':\r\n                    $user-&gt;setGoogleID($socialID);\r\n                    break;\r\n                case 'facebook':\r\n                    $user-&gt;setFacebookID($socialID);\r\n                    break;\r\n            }\r\n            $this-&gt;userManager-&gt;updateUser($user);\r\n        } else {\r\n            \/\/and then login the user\r\n            $checker = new UserChecker();\r\n            $checker-&gt;checkPreAuth($user);\r\n        }\r\n\r\n        return $user;\r\n    }\r\n}<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #ff6600;\"><strong>Related<\/strong>:\u00a0<a style=\"color: #ff6600;\" title=\"What Nobody Tells You When You\u2019re a Junior Developer\" href=\"https:\/\/intelligentbee.com\/blog\/junior-developer\/\" target=\"_blank\" rel=\"noopener\">What Nobody Tells You When You&#8217;re a Junior Developer<\/a><\/span><\/p>\n<p>&nbsp;<\/p>\n<h3>3. Override the User Model<\/h3>\n<p>In our user provider defined above we modified two attributes that do not exist in FOSUser&#8217;s User model: <code>$facebookId<\/code> and <code>$googleId<\/code>. So we need to override the User model and add them.<\/p>\n<pre class=\"toolbar:2 striped:false marking:false ranges:false nums:false nums-toggle:false wrap:true tab-convert:true whitespace-before:1 whitespace-after:1 lang:php decode:true\">namespace AppBundle\\Entity;\r\n\r\nuse FOS\\UserBundle\\Model\\User as BaseUser;\r\nuse Doctrine\\ORM\\Mapping as ORM;\r\n\r\n\/**\r\n * @ORM\\Entity(repositoryClass=\"AppBundle\\Entity\\UserRepository\")\r\n * @ORM\\Table(name=\"fos_user\")\r\n *\/\r\nclass User extends BaseUser\r\n{\r\n    \/**\r\n     * @ORM\\Id\r\n     * @ORM\\Column(type=\"integer\")\r\n     * @ORM\\GeneratedValue(strategy=\"AUTO\")\r\n     *\/\r\n    protected $id;\r\n\r\n    \/**\r\n     * @var string\r\n     *\r\n     * @ORM\\Column(name=\"facebook_id\", type=\"string\", nullable=true)\r\n     *\/\r\n    private $facebookID;\r\n\r\n    \/**\r\n     * @var string\r\n     *\r\n     * @ORM\\Column(name=\"google_id\", type=\"string\", nullable=true)\r\n     *\/\r\n    private $googleID;\r\n    \r\n    \/\/ ...\r\n}\r\n<\/pre>\n<p>Don&#8217;t forget to update your database and then you can move forward to the next step.<\/p>\n<p>&nbsp;<\/p>\n<h3>4. Add Facebook and Google to our\u00a0login and register\u00a0pages<\/h3>\n<p>Now we&#8217;re all set to update our\u00a0Twig files with HWIOauth&#8217;s paths. Since we&#8217;re using FOSUser, we&#8217;ve overridden their <code>register.html.twig<\/code> and <code>login.html.twig<\/code> files and then added the social\u00a0links:<\/p>\n<pre class=\"toolbar:2 striped:false marking:false ranges:false nums:false nums-toggle:false wrap:true tab-convert:true whitespace-before:1 whitespace-after:1 lang:default decode:true \">{# ... #}\r\n&lt;a href=\"{{ path('hwi_oauth_service_redirect', {'service': 'facebook' }) }}\"&gt;\r\n    &lt;span&gt;Facebook&lt;\/span&gt;\r\n&lt;\/a&gt;\r\n&lt;a href=\"{{ path('hwi_oauth_service_redirect', {'service': 'google' }) }}\"&gt;\r\n    &lt;span&gt;Google&lt;\/span&gt;\r\n&lt;\/a&gt;\r\n{# ... #}<\/pre>\n<p>&nbsp;<\/p>\n<p>And there you have it: a fully functional Facebook and Google login and signup system. Now we can go to <span style=\"color: #ff6600;\"><a style=\"color: #ff6600;\" href=\"https:\/\/developers.facebook.com\" target=\"_blank\" rel=\"noopener\">Facebook Developers<\/a><\/span> and <span style=\"color: #ff6600;\"><a style=\"color: #ff6600;\" href=\"https:\/\/console.developers.google.com\/\" target=\"_blank\" rel=\"noopener\">Google Developers Console<\/a><\/span>, create our apps and add our <code>client_id<\/code> and <code>client_secret<\/code> in <code>config.yml<\/code>.\u00a0Have fun!<\/p>\n<p>If you have a different take on this process and can make it even easier, please let us know in the comment section below.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Since pretty much any potential user of an\u00a0app has a Facebook or a Google account, it&#8217;s crucial to have\u00a0a login [&hellip;]<\/p>\n","protected":false},"author":28,"featured_media":1795,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[82],"tags":[],"yst_prominent_words":[273,343,372,455,501,593,1017,1022],"post_mailing_queue_ids":[],"_links":{"self":[{"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/posts\/1753"}],"collection":[{"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/users\/28"}],"replies":[{"embeddable":true,"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/comments?post=1753"}],"version-history":[{"count":4,"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/posts\/1753\/revisions"}],"predecessor-version":[{"id":133292,"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/posts\/1753\/revisions\/133292"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/media\/1795"}],"wp:attachment":[{"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/media?parent=1753"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/categories?post=1753"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/tags?post=1753"},{"taxonomy":"yst_prominent_words","embeddable":true,"href":"https:\/\/intelligentbee.com\/blog\/wp-json\/wp\/v2\/yst_prominent_words?post=1753"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}