Build a one-click registration form powered by Google
Do you know that you can use Google's services to build a one-click registration form for your web site? Everyone with a Google Account can then press a button and instantly sign up for your application with their email, name and photo.
This service is called federated login, and is built on top of the OAuth2 protocol. This is a complex process that involves several data-exchange requests between your server and Google, but we will leave all this to Google's PHP Library, whcih will handle nearly everything on the server side.
Using this login/registration flow can simplify things for both you and your users. Here are some of the benefits:
- No need to create and validate registration and login forms;
- No need for a "forgot password" feature;
- Greatly simplified login/registration flow - you get the person's email, name and photo with only one click;
- The email is already validated by Google, so you don't have to send a validation message.
- Great security on Google's part.
Of course, this will only work if the person has a Google account, so it might make sense to have this in addition to an existing registration system. Let's get started!
Setting things up
The first step is to create a new application through Google's API Console. Follow these instructions for more information. After you complete the process, place the obtained keys in setup.php.
Run the code from schema.sql (you can find it in the download archive) in phpMyAdmin or a different MySQL administration tool. This will create the glogin_users table in your database, which will be used to store account information about the users of your app. After this, write your database connection details to setup.php.
The PHP
The login form we are making, uses Google's Federated login flow. What that means is that visitors of your website follow a link to a Google page, where they give your application access to their accounts, and are redirected back. You then get an access token, which you can use to request information about them. Here is a simplified description of the login flow:
- When the user clicks "Sign in with Google" in our demo, they are taken to Google's Authentication page, where they see what permissions are requested by our application.
- Upon hitting accept, they are redirected back to the site, along with a special code parameter passed in the URL. Our application will use this code to obtain an access token;
- With the access token, the app requests information about the user, which is inserted into the database.
For reading and inserting into the database, I am using a personal favorite - the tiny Idiorm library, which you can find in the library folder.
Our PHP code is organized in the following way:
- index.php - this is the main application file;
- setup.php - this file holds your database connection info, and the keys obtained from Google's API Console;
- The library folder - it contains the Idiorm library, Google's PHP library, and a class for turning timestamps into relative time.
Let us take a look at the code found at the top of index.php:
index.php
require 'setup.php'; // Create a new Google API client $client = new apiClient(); //$client->setApplicationName("Tutorialzine"); // Configure it $client->setClientId($client_id); $client->setClientSecret($client_secret); $client->setDeveloperKey($api_key); $client->setRedirectUri($redirect_url); $client->setApprovalPrompt(false); $oauth2 = new apiOauth2Service($client); // The code parameter signifies that this is // a redirect from google, bearing a temporary code if (isset($_GET['code'])) { // This method will obtain the actuall access token from Google, // so we can request user info $client->authenticate(); // Get the user data $info = $oauth2->userinfo->get(); // Find this person in the database $person = ORM::for_table('glogin_users')->where('email', $info['email'])->find_one(); if(!$person){ // No such person was found. Register! $person = ORM::for_table('glogin_users')->create(); // Set the properties that are to be inserted in the db $person->email = $info['email']; $person->name = $info['name']; if(isset($info['picture'])){ // If the user has set a public google account photo $person->photo = $info['picture']; } else{ // otherwise use the default $person->photo = 'assets/img/default_avatar.jpg'; } // insert the record to the database $person->save(); } // Save the user id to the session $_SESSION['user_id'] = $person->id(); // Redirect to the base demo URL header("Location: $redirect_url"); exit; } // Handle logout if (isset($_GET['logout'])) { unset($_SESSION['user_id']); } $person = null; if(isset($_SESSION['user_id'])){ // Fetch the person from the database $person = ORM::for_table('glogin_users')->find_one($_SESSION['user_id']); }
What is happening here, is that we are checking for the code $_GET parameter. As I mentioned above, this parameter is set by Google when the user is redirected after authorizing the app. In the if block, we are requesting user information and writing it to the database. The id of the user (value of the id key in the database) is written to the session. This is preserved across requests and is used as a flag that the user is logged in.
If you'd like to learn more about OAuth and the login flow, read through Google's page on the subject. There you can also see a table with the fields returned by userinfo get() method.
Near the end, we define a $person variable. It holds an object that is returned by the Idiorm library with properties for each column of the glogin_users table. You can see how this object is used in the next section.
The HTML
The HTML of this example occupies the lower half of index.php. Because of this, we have access to the $person object, which will come handy when printing the name and photo of the user. The page itself is a standard HTML5 document:
index.php
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Google Powered Login Form | Tutorialzine Demo</title> <!-- The stylesheets --> <link rel="stylesheet" href="assets/css/styles.css" /> <link rel="stylesheet" href="http://fonts.googleapis.com/css?family=Open+Sans+Condensed:300,700" /> <!--[if lt IE 9]> <script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script> <![endif]--> </head> <body> <h1>Login Form</h1> <div id="main"> <?php if($person):?> <div id="avatar" style="background-image:url(<?php echo $person->photo?>?sz=58)"></div> <p class="greeting">Welcome, <b><?php echo htmlspecialchars($person->name)?></b></p> <p class="register_info">You registered <b><?php echo new RelativeTime($person->registered)?></b></p> <a href="?logout" class="logoutButton">Logout</a> <?php else:?> <a href="<?php echo $client->createAuthUrl()?>" class="googleLoginButton">Sign in with Google</a> <?php endif;?> </div> </body> </html>
We are checking whether the $person variable holds an object or is empty, and display the username and photo of the user if appropriate. In the other case, we generate and print an Auth URL that points to Google's authentication page for our application.
We're done!
With this our One-click registration form powered by Google is complete! You can build upon this example and embed it as part of your existing websites without much effort. Also, Facebook, Twitter, Github and many more also support OAuth authorization, so you can optionally implement an all-in-one solution that supports all major social networks.
Bootstrap Studio
The revolutionary web design tool for creating responsive websites and apps.
Learn more
It 404's when it is trying to redirect me back.
Sorry about that! It should work now.
Appears that the month is incorrect in the callback address.
Thank you for the heads up! Try it again, it should be fixed.
Nice one. One question, can we implement it in a way to get subscribers for a blog?
Very good tutorial!
Am I missing something? I have it set up to the point of logging in the first time but when I get redirected I just get a blank page. It seems like it is failing at $client->authenticate();
Is there anything in your error log?
Nothing comes back at all to the browser. No HTML no PHP errors or warnings - even with error_reporting set to e_all.
In my MAMP logfile I have this:
PHP Fatal error: Uncaught exception 'apiAuthException' with message 'Error fetching OAuth2 access token, message: 'invalid_grant'' in /Users/xxxxxx/Documents/Websites/AccTimer/google-login-form/includes/google-api-php-client/auth/apiOAuth2.php:105
Stack trace:
0 /Users/xxxxxx/Documents/Websites/AccTimer/google-login-form/includes/google-api-php-client/apiClient.php(138): apiOAuth2->authenticate(Array) 1 /Users/xxxxxx/Documents/Websites/AccTimer/google-login-form/index.php(22): apiClient->authenticate() 2 {main}
thrown in /Users/xxxxxx/Documents/Websites/AccTimer/google-login-form/includes/google-api-php-client/auth/apiOAuth2.php on line 105
There is a stackoverflow discussion here and a Google forum here
It threw the same error when I was running it on localhost. Developing it directly on the web-accessible demo site solved the issue. It is not ideal and there probably is a way to develop locally, but I didn't look into it.
i don't think that there is a way to develop it locally it's a kind of security in those API's ,it's the same case with the Facebook api
Very nice tutorial, Martin.
If users are stored in a local database table, how to handle changes in Google Account (if someone changes a picture or name)?
If someone is already registered and clicks the Sign in button, does it retrieve new data from Google?
Thanks
Nice one,
Now rinse and repeat for Tomcat and Node.js. Does Google have libraries for them too?
Google-Login?!?! No way!
OAuth 2.0 is a fail as his major creator, Eran Hammer, said recently.
By the way he resigns at the same time and encourage people to use OAuth 1 because the last is for people who have very strong securoty knowledge because of the lack of specs.
Maybe some people will answer me : "It's Google, it's safe !"
I will answer them : "Hrrm....."
It's cool, not sure whether google has Java version for this?
This was the tuts i was searching for a long time to connect the Google api.. really thank you for the post :)
Hello Martin,
Error:
Fatal error: Uncaught exception 'PDOException' with message 'SQLSTATE[42S22]: Column not found: 1054 Unknown column 'photo' in 'field list'' in /home/TEST1/public_html/members/SosyalSitelerAuth/Google/includes/idiorm.php:1063 Stack trace: #0 /home/TEST1/public_html/members/SosyalSitelerAuth/Google/includes/idiorm.php(1063): PDOStatement->execute(Array) #1 /home/TEST1/public_html/members/SosyalSitelerAuth/Google/index.php(51): ORM->save() #2 {main} thrown in /home/TEST1/public_html/members/SosyalSitelerAuth/Google/includes/idiorm.php on line 1063
Can you help?
Thank you!
Have you by any chance removed the photo column from the table? The error message states it is missing.
It is working fine when I add new 'photo' column in to table :)
thanks for your help @Martin Angelov
can i run it on localhost? and what things i need change ?
Thank you!
Unfortunately there isn't an easy way to run it locally. There is a workaround that involves modifying your hosts file but I would not recommend it unless you feel comfortable changing system files.
Can you give an example using this on a real world application?
(not using a wordpress site though just standard xthml pages)
Love this! Also would really love it more if you expand it to do Facebook, Twitter as well.
can I install this in a Prestashop site?
It worked. But the picture does not show.
This is awesome tutorial! thx Martin for share
Hi there, have a question:
Which is the right value for $redirect_url?
I'm testing on a production server and don't have idea what the correct value for this
for example if you use the following url:
https://example.com/site/registered.php
in that file (registered.php) must include a redirect to the root of my site?
Could you explain a little better this point? It would be the perfect addition to the tutorial.
Thank you very much.
This is awesome, adding fb and Twitter to this app would be súper awesome.
i keep getting an Error 107 (net::ERR_SSL_PROTOCOL_ERROR): SSL protocol error.
cant work out where im going wrong, any advice would be great thanks,
its hosted here
http://how-e.co.uk/google-login-form/
this was great help thanks alot, any pointers on linking with facebook and twitter as well
Great help and freaking easy to use. I'm gonna try and integrate this system with Facebook, Twitter, and Linked In. Wish me luck! lol.