Social Network Authentication: Google+

on

This article is written for and published on SitePoint.

In the previous part of this series, we created our initial interfaces which we’ll be using for all future parts. In this article, we will integrate Google+ within our application.

You can view the code for all the articles on this Github page.

Google+ login

We start off by creating the following directory: src/SitePoint/SocialLogin/Google. This will be the directory we will be working in, for the rest of the article. Within this directory, we create the GoogleLogin class. This class implements the SocialLoginInterface interface which we created in the previous article. Make sure a property called service is available to store our service in.

Google has some specific needs to make sure we can log in. So make sure we have the following 3 properties present in the class:
– Client id
– key
– callback URL

Since all 3 properties are required for our application to work, our constructor will receive these 3 variables as parameters and set the properties.

Till now, our code looks like this.

<?php

namespace SitePointSocialLoginGoogle;

use SitePointSocialLoginInterfacesSocialLoginInterface;

class GoogleLogin implements SocialLoginInterface {

    /**
     * Google service
     *
     * @var string
     */
    protected $service;

    /**
     * OAuth client ID
     *
     * @var string
     */
    protected $clientId;

    /**
     * OAuth key
     *
     * @var string
     */
    protected $key;

    /**
     * Callback url
     *
     * @var string
     */
    protected $callbackUrl;

    /**
     * Constructor
     *
     * @param $clientId string
     * @param $key string
     * @param $callbackUrl string
     */
    public function __construct($clientId, $key, $callbackUrl)
    {
        $this->clientId = $clientId;
        $this->key = $key;
        $this->callbackUrl = $callbackUrl;
    }

    /**
     * Initializes our service
     */
    public function init()
    {

    }

    /**
     * Returns the login url for the social network
     *
     * @return string
     */
    public function getLoginUrl()
    {
    }

    /**
     * Handles the login callback from the social network
     *
     * @param string $accessCode
     *
     * @return SocialUserInterface
     */
    public function loginCallback($accessCode)
    {

    }
}

Our next step is to create our Google+ service. As you have seen in the previous article, we are using an OAuth library to set up our connection with Google+. We will be using our init method to create the service.

Before we can start, we have to add some use statements to the top of our class.

use OAuthServiceFactory;
use OAuthOAuth2ServiceGoogle;
use OAuthCommonStorageSession;
use OAuthCommonConsumerCredentials;

Everything for our init method is now present. Time to set up our connection with Google+. We do this with the basic examples of the OAuth library we are using.

    /**
     * Initializes our service
     */
    public function init()
    {
        $storage = new Session();
        $serviceFactory = new ServiceFactory();
        $credentials = new Credentials($this->clientId, $this->key, $this->callbackUrl);
        $this->service = $serviceFactory->createService('google', $credentials, $storage, array('userinfo_email', 'userinfo_profile'));

        return $this;
    }

Our service is set now, so we can now continue by filling our other methods from the interface. We will start off with the getLoginUrl method. This method will return a URL which you will be redirecting your user to.

/**
 * Returns the login url for the social network
 *
 * @return string
 */
public function getLoginUrl()
{
    return $this->service->getAuthorizationUri();
}

The next method to define is the loginCallback method. When a user accepts Google+ sharing data with your application, the user will be redirected back to the url you defined as the callbackUrl. When the user is requesting that URL, you should call the loginCallback method from this class.

If everything went well, we can now retrieve data from Google+.

/**
 * Handles the login callback from the social network
 *
 * @return SocialUserInterface
 */
    public function loginCallback()
    {
        $userData = json_decode($this->service->request('https://www.googleapis.com/oauth2/v1/userinfo'), true);
        $googleUser = new GoogleUser($userData);
        return $googleUser;
    }

You might notice we are using a class named GoogleUser here and we are returning a class with the interface SocialUserInterface. However, this class is not yet present.

Google+ user

Every social network returns user data in a different way. Instead of just returning this data, we are going to normalize it so we can easily work with it. We need to create a class named GoogleUser. This class will implement the SocialUserInterface we created in the previous article.

The constructor of this class expects the raw data of Google in this case. In every getter, we will retrieve the data we want from the raw data from Google. In the end, your GoogleUser class could look like this.

<?php

namespace SitePointSocialLoginGoogle;

use SitePointSocialLoginInterfacesSocialUserInterface;

class GoogleUser implements SocialUserInterface {

    /**
     * @var mixed user data
     */
    private $userData;

    /**
     * Constructor.
     *
     * @param $userData mixed Raw social network data for this particular user
     */
    public function __construct($userData)
    {
        $this->userData = $userData;
    }

    /**
     * Get the provider name
     *
     * @return string
     */
    public function getProvider()
    {
        return "google";
    }

    /**
     * Get the UID of the user
     *
     * @return string
     */
    public function getUid()
    {
        if(array_key_exists('id', $this->userData)) {
            return $this->userData['id'];
        }
        return null;
    }

    /**
     * Get the first name of the user
     *
     * @return string
     */
    public function getFirstname()
    {
        if(array_key_exists('given_name', $this->userData)) {
            return $this->userData['given_name'];
        }
        return null;
    }

    /**
     * Get the last name of the user
     *
     * @return string
     */
    public function getLastname()
    {
        if(array_key_exists('family_name', $this->userData)) {
            return $this->userData['family_name'];
        }
        return null;
    }

    /**
     * Get the username
     *
     * @return string
     */
    public function getUsername()
    {
        if(array_key_exists('family_name', $this->userData)) {
            return str_replace(" ", "_", $this->userData['family_name']);
        }

        return null;
    }

    /**
     * Get the emailaddress
     *
     * @return string
     */
    public function getEmailAddress()
    {
        if(array_key_exists('email', $this->userData)) {
            return $this->userData['email'];
        }
        return null;
    }

    /**
     * Get the city
     *
     * @return string
     */
    public function getCity()
    {
        return null;
    }

    /**
     * Get the birthdate
     *
     * @return string
     */
    public function getBirthDate()
    {
        return null;
    }

    /**
     * Get the gender
     *
     * @return string
     */
    public function getGender()
    {

        if(array_key_exists('gender', $this->userData)) {
            return $this->userData['gender'];
        }
        return null;
    }
}

Implementing it into your application

Depending on the framework you are using (if you are using any of course) the implementation can be slightly different. However, I would recommend you have methods like the following below.

public function loginForm() 
{
    //Renders a login form with a button to login with google+ (calls the LoginWithGoogle method).
}
public function loginWithGoogle()
{
    $googleLogin = new GoogleLogin("clientId", "key", "url/loginCallbackGoogle");
    $googleUrl = $googleLogin->init()->getLoginUrl();
    // Redirect user to $googleUrl.
}
public function loginCallbackGoogle()
{
    $googleLogin = new FacebookLogin("clientId", "key", "url/loginCallbackGoogle");
    $googleUser = $googleLogin->init()->loginCallback();
    // You can now either save or merge this user.
    // Next, you can log the user in and redirect him to any page you like
}

Recommendation 1:

Instead of a link in your log in form which redirects you to the loginWithGoogle method, you could also place the Google URL into your view. However, note that you are already creating a connection with Google. This could slow down your page. Especially when using multiple social networks. In general, I would recommend the way above.

Recommendation 2:

If you are going to use multiple social logins, you could easily add a parameter named $socialNetwork to the loginWith and the loginCallback method and add a switch statement inside.

Quick test

If you want to run a quick test to try out the code, clone the Github repository to your local computer and switch to the branch named part2. Fill in your Google+ API details within the testGoogle.php file and run the file from within your browser. When requesting the page, you will be redirected to a Google page, requesting you to share information.

Google requesting to share information

When clicking accept, you will be redirected back to the page you configured as callback URL, showing your first and last name.

Conclusion

In this article we took the base we set in the previous article and worked further on that. We implemented a way to log in with Google+ and made sure we returned an object which normalizes the data you received from Google. In the upcoming article, we will have a look at how we can merge accounts when people are using multiple logins. In follow up articles we will take a look at how we add more social networks to our system.

Leave a Reply

Your email address will not be published. Required fields are marked *