Google+ Sign-In, Sign-Out and removal of user's consent.

This tutorial explains how to implement the Google+ Sign-In feature for your website. I used the One-time code flow as described here Google+ Sign-In for server-side apps.

You can see in action the example used for this tutorial in the Google+ Sign-In example

You can also download the code of the example

We will cover the following topics:

  • What you need before you customize the example
  • Setting up the Google Console for your application
  • Creating a custom Sign-In button
  • Sign out the application
  • Remove the user consent
  • Advices

What you need before you customize the example

Here is what you need to run the example on your website:

  • A working installation of jQuery
  • The Google Api PHP Client library
  • A basic knowledge of AJAX
  • A basic knowledge of PHP
  • A basic understanding of jQuery

Getting jQuery

You can get jQuery by downloading the package from jQuery website and by installing the package on your server or simply using a CDN.
You just need to include the code below in the <head> of your page:

Code
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" />

Note that you can also use JavaScript without jQuery, if you do not want to use jQuery.

Getting the Google API PHP Client library

You can download the library from the GitHub website. Just copy the src subfolder in your website document folder. Personally, I put this in a /libs/google-api in the root of my website folder. Note the dowloadable example includes the Google+ API client library for PHP.

Setting up Google Developper Console

Our application needs to use a configuration in the Google Developper Console. We will configure clientof the API for our application using the following steps:

  • Defining a project
  • Activating the Google+ API
  • Creating a client ID that will be used in your pages and the PHP file that manage the server side flow
  • Customizing the consent screen that will be presented to the user the first time he connects or after the user removes its consent

The tasks above will allow:

  • your web application gets access to the Google+ API
  • allow the users of your application to consent that your application can access their profile informations

Defining a project

1. Click the CREATE PROJECT button.

Create a project in Google Console



2. Give a name to the project

Give a name to Google Console project

Activating the Google+ API

1. From the Google Developper Console click the link to the project you have just created

Google Console project

2. Click on API button

Google Console project - API

3. Find the entry Google+ API and if necessary, click the on OFF to set it ON

4. Come back to the top of the page. The screen should look like this:

Google Console project

Creating a client id

1. Click on Credentials

Google Console Credential

2. Click on CREATE NEW CLIENT ID from the above screen
3. Select «Web application» as application type, fill in your domain name in the «Athorized JavaScript origins» and click Create Client ID:

Google Console Credential - new client definition

4. The screen should look like this:

Google Console Credential - new client

Customizing the consent screen

1. Click on Consent sceen

Google Console Consent Screen

2. Fill in the fields. The right part of the screen helps you to see where the information appears on the consent screen and click on Save

Creating a custom Sign-In button

Now it is time to prepare our page to handle the sign-in button. We'll use a very simple customized button using a link. You can find different ways to define a button in the Google+ Sign-In documenttion.

In this section we will :

  • Configure settings to connect to the Google API
  • Setup counter-measure against CSRF hacking
  • Include the Google+ script in our page
  • Write the script to render the Sign-In button
  • Write the code for the callback function called when the user clicks on the sign-in button
  • Write the HTML tags of the style applied to our custom sign-in button
  • Write the HTML tags for the custom sign-in button
  • Write the code of the script that will run on the server

Note you can view a complete example of those steps within the file google-plus-signin-example.php and the server side script in the file ajx/plus.php. Those files can be found in the downloadable example.

Configuring the connection to the Google API

Update the config.php file

We will now define settings to enable our example to connect to the Google+ API. We will use the client_id and client_secret we have created in the Creating a client id.

1. If you did not download the source code of the example, download the source code of the example now
2. Unzip the package in your website public folder
3. Edit the config/config.php file
4. Define the $clien_id and the $client_secret from the step 4 of Creating a client id:

Code
<?php
/************************************************
 ATTENTION: Fill in these values! Make sure
the redirect URI is to this page, e.g:
http://localhost:8080/user-example.php
************************************************/
\$client_id = 'Place here your client ID';
\$client_secret = 'Place here your client secret';
\$redirect_uri = 'postmessage';
?>

5. Save the config.php file

Our application is now ready to call the Google+ API.
Note that the config/config.php file will be used later to customize the server side PHP script.

Having the client id ready for use

We will manage to have access to our client id that our scripts placed in the web page can use.
We will start a PHP session and include the client_id in a session variable.

1. Put the following code in your web page:

Code
include_once('config/config.php');
//  start session
if (session_status() == PHP_SESSION_NONE) {
    session_start();
    $_SESSION['clientid'] = $client_id;
}

Coding the CSRF counter-measure

It is important that only your pages can use your client account. Remember that hackers having your client number should be able to place calls to the API and decrease the remaining number of calls per day available for you.
To achieve security we will use a token that identify the page when calling the server side script.

1. Put the following code in your web page:

Code
// CSRF Counter-measure
$token = md5(uniqid(rand(), TRUE));
$_SESSION['state'] = $token;

Insert the required JavaScript code for the Sign-In button

1. Include the following code in your <head> section.

Code
<script type="text/javascript">
  	window.___gcfg = {lang: 'en'};
	(function() {
    		var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
    		po.src = 'https://apis.google.com/js/platform.js';
    		var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
	})();
</script>

I use the this script from Customizing the sign-in button from Google without any change.

Rendering the custom sign-in button

Now we will write the code to perform the rendering of our custom button. We'll use PHP script to generate the JavaScripts for two reasons:

  • Session variables vill be used by the JavaScript scripts to get the client_id
  • We will use different script for the button when the user connects after a logout in the same session. I will explain why later.

Assume for now that the button will be rendered using the render() function.

1. Put the following code in the web page:

Code
if (!isset($_SESSION['logout'])) {
	$gScript = 'po.src = 'https://plus.google.com/js/client:plusone.js?onload=render';';
} else {
	$gScript = 'po.src = 'https://plus.google.com/js/client:plusone.js';';
}
echo '<script type="text/javascript">
	(function () {
		var po = document.createElement('script');
		po.type = 'text/javascript';
		po.async = true;
		' . $gScript . '
		var s = document.getElementsByTagName('script')[0];
		s.parentNode.insertBefore(po, s);
	})();
</script>
<script type="text/javascript">
	function render() {
		gapi.signin.render('customBtn', {
			'callback': 'signinCallback',
			'clientid': '' . \$_SESSION['clientid'] . '',
			'cookiepolicy': 'single_host_origin',
			'requestvisibleactions': 'http://schemas.google.com/AddActivity',
			'scope': 'https://www.googleapis.com/auth/plus.login email'
		});
	}
</script>

The first script in the code above create an element for the google script that will perform the rendering of the sign-in button.

The second JavaScript script includes the render function for the custom button. Note the HTML id customBtn will be used to apply styles to our custom sign-in button. Note the use of the client_id session vatiable to pass the $client_id stored in the config/config.php file. The callback data defines the callback function that will be called when the user clicks on the sign-in button, in our case signinCallback. Do not forget to add the scopesaccording to your needs. Remember the scope data defines the data that the user will be invited to consent. Our application will be able to retrieve only the data for which the user has given his consent.

Write the script for the callback function

We will now write the signinCallback callback function that calls the PHP script onthe server to render items that will be displayed when the user is signed in.

1. Put this code in the web page:

Code
<script type="text/javascript">
	function signinCallback(authResult) {
		if (authResult['code']) {
			$.post( "/ajx/plus.php?storeToken",
				{ code: authResult['code'], state: "' . $_SESSION['state'] . '"},
				function( data ) {
					$('#gPlus').empty().append( data );
				}
			);
		}
	};

If the user gives its consent in the consent screen, The Google script passes an object containing a code that the server side script will use to get the access token that will allow to retrieve user data using the Google+ API.

The $.post request to the server side script /ajx/plus.php instructs the server side script to request an access token using the code generated after the user gave its consent. We also pass the state token for CSRF counter-measure to the server side script.

The call to the $.post implements a function that fill the <div id="gplus"> with the data returned by the server side script.

Writing the style for the custom sign-in button

1. Put the style tags

Code
<style type="text/css">
	#customBtn {cursor: pointer;}
	#customBtn:hover {text-decoration: underline; cursor: hand;}
</style>

Please note a strange thing: the cursor: pointer; style have to be set for the #customBtn, otherwise the hand cursor does not appear on a hover event.

Writing HTML tags for the Sign-in button

This code checks if there is an access token in the access_token session variable. If it is the case, the user is signed in and we display the data we received previously from the server side script. We will discuss this topic later.

1. Put the following code in your web page:

Code
if (isset($_SESSION['access_token'])) {
	if (isset($_SESSION['logout'])) {
		$gPlus = $gPlusWhenLogout;
	} else {
		if (isset($_SESSION['givenName']))
		$gPlus = '<div id="gPlusNav">
			<a href="https://plus.google.com/u/0/">+'
			 . $_SESSION['givenName']  . '</a>   
			<a href="' . $_SESSION['profileURL'] . '"a>
			<img src="../img/gphotocache.png" style="background:url(''
			 . $_SESSION['photo'] . '');"</a>   
			<a onclick="gvnSignOut(); return false;" href="#">Disconnect me</a>   
			<a onclick="revokeAccess(); return false;" href="#">Remove my consent</a>
			</div>';
	}
} else {
	if (isset($_SESSION['logout'])) {
		$gPlus = $gPlusWhenLogout;
	} else {
		$gPlus = '<div id="gSignInWrapper">
    				<div id="customBtn" class="customGPlusSignIn">
					<a>+Sign In</a>
				</div>
			</div>';
	}
}

For the moment we'll look at the part in red within the code above. The $gPlus contains the HTML tags to display the custom Sign-In button

2. In the <body> of your web page, put the following code:

Code
echo "<div id = \"gPlus\" style=\"border: 1px solid; padding: 10px\">
	$gPlus
      </div>";

The code above displays the custom Sign-In button if the user is not signed in, otherwise it displays the user's data.

Writing the code for the server side script

Now, will prepare the server side PHP scripts. The full code can be found in the ajx/plus.php file.

This section will use the Google Api PHP Client library. Do not forget to install it or copy it from the downloadable example.

We will perform the following tasks:

  • Checking if there is a CSRF hacking
  • Creating a client for the Google API
  • Requesting an access token
  • Calling the API

Checking if there is a CSRF hacking

1. To ensure we do not have a Cross Site Request Forgery (CSRF) hacking, we will insert the following code:

Code
session_start();
/************************************************
 Check CSRF attack
*************************************************/
if (isset($_POST['state']) && isset($_SESSION['state'])) {
	if (!($_POST['state'] == $_SESSION['state'])) {
		header($_SERVER['SERVER_PROTOCOL'] . ' Unauthorized' , true, 401);
		exit;
	}
} else {
	header($_SERVER['SERVER_PROTOCOL'] . ' Unauthorized' , true, 401);
	exit;
}

This code checks if the token for counter-measure against CSRF attacks is passed to the POST request and that it is the same as the token stored in the session variable before performing any other task.

Creating a Google API Client

The code above initializes a Google Client object using the config/config.php file :

Code
set_include_path("../libs/google-api/src/" . PATH_SEPARATOR . get_include_path());

include_once '../config/config.php';
require_once 'Google/Client.php';
require_once 'Google/Service.php';
require_once 'Google/Service/Plus.php';
  
/************************************************
  Make an API request on behalf of a user. In
  this case we need to have a valid OAuth 2.0
  token for the user, so we need to send them
  through a login flow. To do this we need some
  information from our API console project.
 ************************************************/
$client = new Google_Client();
$client->setClientId($client_id);
$client->setClientSecret($client_secret);
$client->setRedirectUri($redirect_uri);
$client->addScope("https://www.googleapis.com/auth/plus.login");
$client->addScope("email");
		

Do not forget to call addScope method for each scope you need. The above example comes from the examples in the Google API Client library

Request an access token

In this step we will authenticate with the code sent by our web page when the user clicked on the Sign-In button. We store the access_token in a session variable that will be used in our web page. This is important, because if you put the sign-in, the sign-out and the removal of consent in all your web pages (like a navigation bar), you do not have to login or call the server side script each time you navigate from one page to another:

Code
/************************************************
 If asked to store the token, get a token and 
 saveit to the session.
 
************************************************/
if (isset($_REQUEST['storeToken'])) {
	
	/************************************************
	 If we have a code back from the OAuth 2.0 flow,
	we need to exchange that with the authenticate()
	function. We store the resultant access token
	bundle in the session.
	************************************************/
	if (isset($_POST['code'])) {
		$client->authenticate($_POST['code']);
		$_SESSION['access_token'] = $client->getAccessToken();
		unset($_SESSION['logout']);
	}
}

Calling the API

In this section we will call the Google API to collect the information about the user that connects. The example code retrieves the given name, the Google+ URL, the profile picture and the URL of user's profile. The data is returned as an HTML flow to be displayed by the web page that called the API:

Code
/************************************************
  If we have an access token, we can make
  requests, else we generate an error
 ************************************************/
if (isset($_SESSION['access_token']) && $_SESSION['access_token']) {
  $client->setAccessToken($_SESSION['access_token']);
  if ($_SESSION['access_token']) {
  	$client->setAccessToken($_SESSION['access_token']);
  	$PlusService = new Google_Service_Plus($client);
  	$me = new Google_Service_Plus_Person();
  	$me = $PlusService->people->get('me');
 	$PlusPersonEMails = new Google_Service_Plus_PersonEmails();
 	$PlusPersonEMails = $me->getEmails();
 	foreach($PlusPersonEMails as $em) {
 		if($em->type == "account") {
 			$user_email = $em->value;
 		}
 	}
  	$PlusPersonName = new Google_Service_Plus_PersonName();
  	$PlusPersonName = $me->getName();
  	$PlusPersonImage = new Google_Service_Plus_PersonImage();
  	$PlusPersonImage = $me->getImage();
  	$user_id = $me->id;
  	$user_name = filter_var($me->displayName, FILTER_SANITIZE_SPECIAL_CHARS);
	$user_gender = substr($me->gender,0,1);
  	$profile_url = $me->url;
  	$profile_image_url = filter_var($PlusPersonImage->getUrl(), FILTER_VALIDATE_URL);
  	$parsed_url = parse_url($profile_image_url);
  	$ImgResized	= $parsed_url['scheme']
		 . '://' . $parsed_url["host"]
		 . $parsed_url["path"]
		 . '?sz=25';
  	$given_name	= filter_var($PlusPersonName->getGivenName(), FILTER_SANITIZE_SPECIAL_CHARS);
  	$_SESSION['token'] = $client->getAccessToken();
  	$_SESSION['givenName'] = $given_name;
  	$_SESSION['Name'] = $user_name;
  	$_SESSION['id'] = $user_id;
  	$_SESSION['photo'] = $ImgResized;
  	$_SESSION['profileURL'] = $profile_url;
  	$_session['gender'] = $user_gender;
  	$_session['email'] = $user_email;
  	echo '<div id="gPlusNav">
			<a href="https://plus.google.com/u/0/">+'
				 . $_SESSION['givenName']
				 . </a> '   
			<a href="' . $_SESSION['profileURL']
				 . '" class="dropdown-toggle" data-toggle="dropdown">
			<img src="../img/gphotocache.png" style="background:url(''
				. $_SESSION['photo']
				. '');"></a>   
			<a onclick="gvnSignOut(); return false;"
					href="#">Disconnect me</a>   
			<a onclick="revokeAccess(); return false;"
					href="#">Remove my consent</a>
		</div>';
  } else {
	header("HTTP/1.1 401 Bad token");
  	exit;
  }
} else {
  header("HTTP/1.1 401 Bad token");
}

The code is not optimized, but it is just a way to show how the library works. I also include code to get information that is not directly used by the client web page. It is just to show you how to get the information. I also passed the information in session variables. The idea is to reuse the returned information in a navigation bar on each page of our website. In this case, you just have to call the API one time. It is obvious that this is not the better way to work, but for people that are not familiar with more complex data flows like XML or JSON flow, the example remains understandable. In a real web site you probably would like a more robust technique to return a flow of data.

Signing Out

First, let's look at the behavior that we expect during a user's session:

  • When the user visits the site, if he previously gave his consent, we would like he is automatically logged in
  • When the user disconnects, we want to show the sign-in button again giving him the opportunity to sign in again
  • If the user signs out, during the session we do not want the an automatic sign-in when refreshing the page, or when navigating to other pages where the Sign-In button appears

Refine the Sign-In button

Personalized Sign-In button we discussed in the previous steps allows the user that gives its consent to connect automatically (if he is logged in Google+). Because it is not the behavior we expect, we will present a button the user will click if he want to connect again. We will use the JavaScript API to achieve the task:

Code
$gPlusWhenLogout = '<div id="gSignInWrapper">
		<div id="customBtn">
			<a onclick="gapi.auth.signIn({'clientid' : ''
				 . $_SESSION['clientid'] . '',
			'cookiepolicy' : 'single_host_origin',
			'callback' : 'signinCallback',
			'requestvisibleactions' : 'http://schemas.google.com/AddActivity',
			'scope' : 'https://www.googleapis.com/auth/plus.login email'});
			$('#customBtn').hide();">+Sign In</a>
		</div>
	</div>';
	
	if (isset($_SESSION['access_token'])) {
		if (isset($_SESSION['logout'])) {
			$gPlus = $gPlusWhenLogout;
		} else {
			...
	

The code above shows how to implement a sign-in button without automatic sign-in in case of page refresh or navigation to other pages. We prepare the HTML tags for the button and then we display it if the user previously signed out. Look at the google-plus-signin-example.php file for the full code.
The button is a simple link that calls the gapi.auth.signIn() function. Data used by this function are the same as for the Custom Sign-In button previously commented. Finally, we hide the button using jQuery.

There is one issue with the call to the gapi.auth.signIn() function: There is a flashing window that pops up. (It seems it is the consent window). This is another reason why we use this technique only when the user previously signed out. I submitted the problem, but it seems this is an improvement for Google.

Client side coding

Write the sign-out script

1. Put the script in the <head> section of your web page:

Code
<script type="text/javascript">
	function gvnSignOut() {
		$.post( "/ajx/plus.php?logout", {state: "' . $_SESSION['state'] . '"},
			function( data ) {
				$('#gPlus').empty().append( data );
			});
			gapi.auth.signOut();
		};
</script>
		

The above script call the server side PHP script to sign-out of our application. Then, the script shows the Sign-In button again using the HTML code returned by the server side script.

The sign-out button

We'll now come back to the button the user click to sign-out. You can find the full code in the google-plus-signin-e.php file:

Code
if (isset($_SESSION['access_token'])) {
	if (isset($_SESSION['logout'])) {
		$gPlus = $gPlusWhenLogout;
	} else {
		if (isset($_SESSION['givenName']))
			$gPlus = '<div id="gPlusNav">
						<a href="https://plus.google.com/u/0/">+'
							 . $_SESSION['givenName']
							 . '</a>   
						<a href="' . $_SESSION['profileURL'] . '"a>
						<img src="../img/gphotocache.png" style="background:url(''
							 . $_SESSION['photo']
							 . '');"</a>   
						<a onclick="gvnSignOut(); return false;"
							 href="#">Disconnect me</a>   
						<a onclick="revokeAccess(); return false;"
							 href="#">Remove my consent</a>
					</diva>';
	}
	...

The link highlighted in red in the above script calls the sign-out script when the user clicks on the link.

Write the server side code for the sign out

We will add the following code to the server side script. You can find the full code in the ajx/plus.php file:

Code
$gPlusWhenLogout = 
	'<div id="gSignInWrapper">
		<div id="customBtn">
			<a onclick="gapi.auth.signIn({'clientid' : '' . $_SESSION['clientid'] . '',
				'cookiepolicy' : 'single_host_origin',
				'callback' : 'signinCallback',
				'requestvisibleactions' : 'http://schemas.google.com/AddActivity',
				'scope' : 'https://www.googleapis.com/auth/plus.login email'});
				$('#customBtn').hide();">+Sign In</a>
			</div>
		</div>';

/************************************************
 Handles logout
*************************************************/

if (isset($_REQUEST['logout'])) {
	unset($_SESSION['access_token']);
	$_SESSION['logout'] = 1;
	echo $gPlusWhenLogout;
	exit;
}

The code above destroys the access_token session variable, positions the sign-out flag and returns the HTML tags for the sign-in button

Removing user's consent

We will now give the user the ability to remove the consent that allows our application to access to the user's data. The removal of the user's consent forces the next sign-in to prompt the consent screen. The code works the same way as the sign-out button.

Write script for removal of consent

1. Put the script in the <head> section of your web page:

Code
	<script type="text/javascript">
	function revokeAccess() {
		$.post("/ajx/plus.php?revoke", {state: "' . $_SESSION['state'] . '"},
			function( data ) {
				$('#gPlus').empty().append( data );
			}
		);
	</script>
		

The above script call the server side PHP script to sign out of our application. Then, the script shows the Sign-In button again using the HTML code returned by the server side script.

The sign-out button

We will now come back to the button the user click to remove its consent. You can find the full code in the google-plus-signin-example.php file:

Code
if (isset($_SESSION['access_token'])) {
	if (isset($_SESSION['logout'])) {
		$gPlus = $gPlusWhenLogout;
	} else {
		if (isset($_SESSION['givenName']))
			$gPlus = 
		'<div id="gPlusNav">
			<a href="https://plus.google.com/u/0/">+'
				 . $_SESSION['givenName']
				 . '</a>   
			<a href="' . $_SESSION['profileURL'] . '"a>
			<img src="../img/gphotocache.png" style="background:url(''
				 . $_SESSION['photo']
				 . '');"</a>   
			<a onclick="gvnSignOut(); return false;"
					 href="#">Disconnect me</a>   
			<a onclick="revokeAccess(); return false;"
					 href="#">Remove my consent</a>
		</diva>';
	}
	...

The link highlighted in red in the above script calls the script that remove the consent when the user clicks on it.

Write the code to remove the consent on the server side

We will add the following code to the server side script. You can find the full code in the ajx/plus.php file:

Code
/************************************************
 Handles revoke
*************************************************/

if (isset($_REQUEST['revoke'])) {
	$_SESSION['logout'] = 1;
  	$token = json_decode($_SESSION['access_token'])->access_token;
  	$discon = $client->revokeToken($token); 
	unset($_SESSION[<'access_token']);
	echo $gPlusWhenLogout;
	exit;
}

The code above destroys the access_token session variable, positions the sign-out flag, calls the API method revokeToken() to force consent when the user connects again and returns the HTML tags for the sign-in button.

Advices

You may experience issues with Microsoft Internet Explorer when running the server-side script on a localhost test installation. Fortunately, those issues disapeared when uploading to a server. I advice you to fine tune your development using FireFox and Google Chrome and perform test with Internet Explorer on a server.

Get in touch!

We'd love to hear from you, what you think about this page or what we can do for you.

Contact Us

View this page with IE8+, Mozilla Firefox, Safari, Chrome and Mobiles

Last modificaton on 21 May 2015 by St├ęphane Van Nerom

© 2006-2014 - GVN - All rights reserved
v2.0.14