Integrating "Sign In With Google" Functionality To An Application

This article demonstrates how to integrate "Log in using Google account" functionality to your web application. There are many ways to integrate it. Here, I will explain how to integrate using REST API. Before you can integrate Google sign-In into your website, you must create a Google API Console project and client ID, which you need to call the sign-in API.

To understand Google API and OAuth validation, visit https://developers.google.com/identity/protocols/OpenIDConnect  and  https://developers.google.com/identity/sign-in/web/sign-in 

Brief request summary: Move top to bottom
 
To create a project, follow the below steps.
  1. Log in to your Google account.
  2. Go to the URL https://console.developers.google.com 
  3. Click on "Create Project" button.


  4. Give your project a name.


  5. Go to "Credentials" section.

     

  6. Click on "OAuth consent screen" and enter necessary details followed by clicking on "Save" option.


  7. Now, go to the "Credentials" section and click on "Create Credential" button.

Enter Authorized redirect URL. This URL should be your app API which will capture the access code or error code returned from Google API as a parameter. Then, click on Create button. On the next page, you will be provided with a "Client Id" and "Client Secret key". Save these values separately. We will use these keys later in our web application to validate our request. Now your app is ready to use.
Now, we will test this functionality using an ASP.NET MVC application (.NET Framework).
  1. Create an MVC project using VisualStudio IDE.
  2. Add Newtonsoft.JSON library from NuGet Package Manager to your project. This library will be used to serialize and deserialize JSON object.
  3. Add System.Net.Http assembly using "Add a reference" option. This will be used to request URLs using HttpClient class instance.
Add a Controller named Home and add the following code.

HomeController.cs
  1. using IntegrateGoogleSignIn.Models;  
  2. using LogInUsingLinkedinApp.Models;  
  3. using Newtonsoft.Json;  
  4. using System;  
  5. using System.Collections.Generic;  
  6. using System.Configuration;  
  7. using System.Net.Http;  
  8. using System.Threading.Tasks;  
  9. using System.Web.Mvc;  
  10.   
  11. namespace IntegrateGoogleSignIn.Controllers  
  12. {  
  13.     public class HomeController : Controller  
  14.     {  
  15.         private string ClientId = ConfigurationManager.AppSettings["Google.ClientID"];  
  16.         private string SecretKey = ConfigurationManager.AppSettings["Google.SecretKey"];  
  17.         private string RedirectUrl = ConfigurationManager.AppSettings["Google.RedirectUrl"];  
  18.   
  19.         /// <summary>    
  20.         /// Returns login page if user is not logged in else return user profile    
  21.         /// </summary>    
  22.         /// <returns>return page</returns>  
  23.         public async Task<ActionResult> Index()  
  24.         {  
  25.             string token = (string)Session["user"];  
  26.             if (string.IsNullOrEmpty(token))  
  27.             {  
  28.                 return View();  
  29.             }  
  30.             else  
  31.             {  
  32.                 return View("UserProfile", await GetuserProfile(token));  
  33.             }  
  34.         }  
  35.   
  36.         /// <summary>  
  37.         /// Hit Google API to get access code  
  38.         /// </summary>  
  39.         public void LoginUsingGoogle()  
  40.         {  
  41.            Response.Redirect($"https://accounts.google.com/o/oauth2/v2/auth?client_id={ClientId}&response_type=code&scope=openid%20email%20profile&redirect_uri={RedirectUrl}&state=abcdef");  
  42.         }  
  43.   
  44.         [HttpGet]  
  45.         public ActionResult SignOut()  
  46.         {  
  47.             Session["user"] = null;  
  48.             return View("Index");  
  49.         }  
  50.   
  51.         /// <summary>  
  52.         /// Listen response from Google API after user authorization  
  53.         /// </summary>  
  54.         /// <param name="code">access code returned from Google API</param>  
  55.         /// <param name="state">A value passed by application to prevent Cross-site request forgery attack</param>  
  56.         /// <param name="session_state">session state</param>  
  57.         /// <returns></returns>  
  58.         [HttpGet]  
  59.         public async Task<ActionResult> SaveGoogleUser(string code, string state, string session_state)  
  60.         {  
  61.             if(string.IsNullOrEmpty(code))  
  62.             {  
  63.                 return View("Error");  
  64.             }  
  65.   
  66.             var httpClient = new HttpClient  
  67.             {  
  68.                 BaseAddress = new Uri("https://www.googleapis.com")  
  69.             };  
  70.             var requestUrl = $"oauth2/v4/token?code={code}&client_id={ClientId}&client_secret={SecretKey}&redirect_uri={RedirectUrl}&grant_type=authorization_code";  
  71.   
  72.             var dict = new Dictionary<string, string>  
  73.             {  
  74.                 { "Content-Type""application/x-www-form-urlencoded" }  
  75.             };  
  76.             var req = new HttpRequestMessage(HttpMethod.Post, requestUrl) { Content = new FormUrlEncodedContent(dict) };  
  77.             var response = await httpClient.SendAsync(req);  
  78.             var token = JsonConvert.DeserializeObject<GmailToken>(await response.Content.ReadAsStringAsync());  
  79.             Session["user"] = token.AccessToken;  
  80.             var obj = await GetuserProfile(token.AccessToken);  
  81.   
  82.             //IdToken property stores user data in Base64Encoded form  
  83.             //var data = Convert.FromBase64String(token.IdToken.Split('.')[1]);  
  84.             //var base64Decoded = System.Text.ASCIIEncoding.ASCII.GetString(data);  
  85.   
  86.             return View("UserProfile", obj);  
  87.         }  
  88.   
  89.         /// <summary>  
  90.         /// To fetch User Profile by access token  
  91.         /// </summary>  
  92.         /// <param name="accesstoken">access token</param>  
  93.         /// <returns>User Profile page</returns>  
  94.         public async Task<UserProfile> GetuserProfile(string accesstoken)  
  95.         {  
  96.             var httpClient = new HttpClient  
  97.             {  
  98.                 BaseAddress = new Uri("https://www.googleapis.com")  
  99.             };  
  100.             string url = $"https://www.googleapis.com/oauth2/v1/userinfo?alt=json&access_token={accesstoken}";  
  101.             var response = await httpClient.GetAsync(url);  
  102.             return JsonConvert.DeserializeObject<UserProfile>(await response.Content.ReadAsStringAsync());  
  103.         }  
  104.     }  
  105. }  

Add a Models folder and add the following models. These models will be used to store the information received from Google API.

UserProfile.cs 
  1. using Newtonsoft.Json;  
  2.   
  3. namespace IntegrateGoogleSignIn.Models  
  4. {  
  5.   
  6.     //* JsonProperty(PropertyName = "name") attribute used here    
  7.     //* to map json property name with object property name     
  8.     //* while deseralizing a json into object   
  9.     public partial class UserProfile  
  10.     {  
  11.         [JsonProperty("id")]  
  12.         public string Id { get; set; }  
  13.   
  14.         [JsonProperty("email")]  
  15.         public string Email { get; set; }  
  16.   
  17.         [JsonProperty("verified_email")]  
  18.         public bool VerifiedEmail { get; set; }  
  19.   
  20.         [JsonProperty("name")]  
  21.         public string Name { get; set; }  
  22.   
  23.         [JsonProperty("given_name")]  
  24.         public string GivenName { get; set; }  
  25.   
  26.         [JsonProperty("family_name")]  
  27.         public string FamilyName { get; set; }  
  28.   
  29.         [JsonProperty("link")]  
  30.         public string Link { get; set; }  
  31.   
  32.         [JsonProperty("picture")]  
  33.         public string Picture { get; set; }  
  34.   
  35.         [JsonProperty("gender")]  
  36.         public string Gender { get; set; }  
  37.   
  38.         [JsonProperty("locale")]  
  39.         public string Locale { get; set; }  
  40.     }  
  41. }  
GmailToken.cs
  1. using Newtonsoft.Json;  
  2.   
  3. namespace LogInUsingLinkedinApp.Models  
  4. {  
  5.     public class GmailToken  
  6.     {  
  7.         [JsonProperty("access_token")]  
  8.         public string AccessToken { get; set; }  
  9.   
  10.         [JsonProperty("token_type")]  
  11.         public string TokenType { get; set; }  
  12.   
  13.         [JsonProperty("expires_in")]  
  14.         public long ExpiresIn { get; set; }  
  15.   
  16.         [JsonProperty("id_token")]  
  17.         public string IdToken { get; set; }  
  18.     }  
  19. }  

Now, add views for log in page and display user profile. 

File : Index.cshtml : For login using Google page 
  1. @{  
  2.     Layout = null;  
  3. }  
  4.   
  5. <!DOCTYPE html>  
  6.   
  7. <html>  
  8. <head>  
  9.     <meta name="viewport" content="width=device-width" />  
  10.     <title>Login using Google</title>  
  11. </head>  
  12. <body style="background-color:#f3f3f3;">  
  13.     <div style="align-items:center;align-items:center;padding:50px;border:1px double #3d2487;width:260px;background-color:white">  
  14.         <h2>Hi Guest</h2>  
  15.         <p>  
  16.             <a href="~/Home/LoginUsingGoogle" ><img src="~/Resources/login-google.png" style="width:215px;height:41px" /></a>  
  17.         </p>  
  18.     </div>  
  19. </body>  
  20. </html>  
File : UserProfile.cshtml : To display user data
  1. @model IntegrateGoogleSignIn.Models.UserProfile  
  2.   
  3. @{  
  4.     Layout = null;  
  5. }  
  6.   
  7. <!DOCTYPE html>  
  8.   
  9. <html>  
  10. <head>  
  11.     <meta name="viewport" content="width=device-width" />  
  12.     <title>UserProfile</title>  
  13. </head>  
  14. <body style="border:0px;background-color:black;color:white">  
  15.     <div>  
  16.         <table style="padding:20px">  
  17.             <tr>  
  18.                 <td>  
  19.                     <img src="@Model.Picture" width="300" height="300" style="border-radius:200px"/>  
  20.                 </td>  
  21.                 <td style="padding:20px">  
  22.                     <p><b style="color:yellow">@Html.DisplayNameFor(model => model.Email) : </b> @Html.DisplayFor(model => model.Email)</p>  
  23.                     <p><b style="color:yellow">@Html.DisplayNameFor(model => model.VerifiedEmail) : </b> @Html.DisplayFor(model => model.VerifiedEmail)</p>  
  24.                     <p><b style="color:yellow">@Html.DisplayNameFor(model => model.Name) : </b> @Html.DisplayFor(model => model.Name)</p>  
  25.                     <p><b style="color:yellow"> @Html.DisplayNameFor(model => model.GivenName): </b>@Html.DisplayFor(model => model.GivenName) </p>  
  26.                     <p><b style="color:yellow">@Html.DisplayNameFor(model => model.FamilyName): </b>@Html.DisplayFor(model => model.FamilyName) </p>  
  27.                     <p><b style="color:yellow">@Html.DisplayNameFor(model => model.Link) : </b> <a href="@Html.DisplayFor(model => model.Link)">@Html.DisplayFor(model => model.Link)</a> </p>  
  28.                     <p><b style="color:yellow"> @Html.DisplayNameFor(model => model.Gender) : </b>  @Html.DisplayFor(model => model.Gender)</p>  
  29.                     <p><b style="color:yellow">@Html.DisplayNameFor(model => model.Locale) : </b>@Html.DisplayFor(model => model.Locale) </p>  
  30.                 </td>  
  31.             </tr>  
  32.         </table>  
  33.   
  34.     </div>  
  35. </body>  
  36. </html>  
File : Error.cshtml : To display error message
  1. @{  
  2.     Layout = null;  
  3. }  
  4.   
  5. <!DOCTYPE html>  
  6.   
  7. <html>  
  8. <head>  
  9.     <meta name="viewport" content="width=device-width" />  
  10.     <title>Error</title>  
  11. </head>  
  12. <body>  
  13.     <h4>  
  14.         Oops ! Something went wrong  
  15.     </h4>  
  16. </body>  
  17. </html>  

In Web.Config file, add the following configuration.

  1. <!--Configuration-->  
  2. <add key="Google.ClientID" value="613508012667-30n28lfgp1djq6ias02fhfm88laj3mds.apps.googleusercontent.com"/>  
  3. <add key="Google.SecretKey" value="GAcn_buF3lJcAlK7TBf8LK-Q"/>  
  4. <add key="Google.RedirectUrl" value="http://localhost:52986/Home/SaveGoogleUser"/>  

Enter your own Client id and Secret key that you received while creating the key in Google developer portal. https://console.developers.google.com.

Run the Project and hit Url: http://localhost:52986/Home/Index and click on "Login using Google" button.

Now, the Google API will ask for your permission to grant access to your app. Click on "Allow" button and you will see your basic details on our user profile page.

The user data response you will get from Google API will look like this. 
  1. {  
  2.  "id""118150916278741694330",  
  3.  "email""[email protected]",  
  4.  "verified_email"true,  
  5.  "name""tarun kumar",  
  6.  "given_name""tarun",  
  7.  "family_name""kumar",  
  8.  "link""https://plus.google.com/118150916278741694330",  
  9.  "picture""https://lh3.googleusercontent.com/-3fcBPvz0ZQI/AAAAAAAAAAI/AAAAAAAAANY/kk8e3oOWIlY/photo.jpg",  
  10.  "gender""male",  
  11.  "locale""en"  
  12. }  

Our code will deserialize this JSON data into an object named UserProfile.

User details page will look like the following one.

 

As the source code is larger than the upload limit, it is first compressed using the 7-Zip compressor and then it is zipped. Please first unzip and then decompress using the 7-Zip software.
 
For any queries and feedback, please write in the comment box. Check "Login using LinkedIn". In an upcoming coming article, I will demonstrate how to integrate "Login using Facebook".


Similar Articles