ASP.NET Core - Implement Google One Tap Sign In

ASP.NET Core - Implement Google One Tap Sign In

Raymond Tang Raymond Tang 0 1823 1.38 index 5/18/2021

Google one tap is a cross-platform sign-in mechanism for Web and Android. It enables Google users to sign up to a third party services like website literally with one tap only.  This article provides detailed steps to implement this sign-in mechanism for ASP.NET Core website.

About Google one tap sign-up

For website implemented Google one tag sign up or sign in like Kontext, a popup window will show up if the user already signed into Google accounts. Once the user click 'Continue as ...' button, Google will return credential details to the callback service; the credential can be used to retrieve more information about the Google user.

Now let's start to implement Google one tap in an ASP.NET core application.

infoASP.NET Identity can be used to keep one tap returned user information as local account. For more information about Identity Core, please refer to official documentation Introduction to Identity on ASP.NET Core | Microsoft Docs. This article won't cover details about identity.

Register Google API client

The first step is to register a Google API client ID and configure OAuth Consent Screen. Refer to the official documentation: Get your Google API client ID  |  Sign In With Google. This step is required for normal Google sign-in and one tap sign-in.

The main tasks involved are:

  1. Create OAuth client ID credentials via Google APIs console.
  2. Configure OAuth Consent Screen via OAuth consent screen.

There are two data items can be used later on: ClientIdand ClientSecret.  ClientSecret is not mandatory for Google One Tap sign-in but is required for Google Sign-in (Google external login setup in ASP.NET Core | Microsoft Docs).

 "Google": {
      "ClientId": "***.apps.googleusercontent.com",
      "ClientSecret": "***"    }

Add client scripts

Now we can add Google One Tap required client scripts into client pages.

First we need to add Google JavaScript file into HTML header section of Razor pages or MVC views.

<script src="https://accounts.google.com/gsi/client" async defer></script>

And then add the following HTML to the pages that you want to show one tag sign-in popup window:

<div id="g_id_onload"
             data-client_id="***"
             data-login_uri='/GoogleOneTap'>
</div>

The value for data-client_id attribute need to be replaced with Google OAuth client Id created in the previous steps. For the second attribute data-login_uri that is the callback URI once the authentication is successful. In the example, URI /GoogleOneTap is used as callback handler. We will add this controller or Razor page in next step.

Add callback handlers

Let's add a Razor page named GoogleOneTap. In this Razor page, we need to implement a handler for POST HTTP request. For MVC project, please follow similar steps.

/// <summary>
/// Google one tap sign in handler
/// </summary>
/// <returns></returns>
public async Task<IActionResult> OnPostAsync()
{
}

This function will be invoked once Google authenticate the user successfully and it will send a POST HTTP request to this Razor page. In the POST form body, there are two critical elements:

  • g_csrf_token: CSRF token.
  • credential: the returned credential that can be used in Google APIs for validation.

Before implementing the function, we need to add two packages into the ASP.NET Core web project: Google.Apis.Auth and Microsoft.AspNetCore.Authentication.Google. The first package will be used to retrieve user details like Email, GivenName, FamilyName, JWT ID token, etc. The second package will be used to sign-in to ASP.NET Identity.

Implement the callback function

The main steps for implementing the callback function involves:

  1. Verify CSRF token.
  2. Verify returned credential (ID token).
  3. Sign in to ASP.NET core Identity service using SignInManager with returned payload details.
  4. If sign-in is not successful, it means the local account is not created yet in Identity; thus UserManager can be used to create local account and add external login details (scope subject) with provider as Google and then sign-in again before returning to the previous visited URL.
  5. If sign-in is successful, return to the previous visited URL (ReturnUrl) before one tap sign in.

The sample code looks like the following code snippet:

/// <summary>
/// Google one tap sign in handler
/// </summary>
/// <returns></returns>
public async Task<IActionResult> OnPostAsync()
{
    // Validate Google CSRF first since we turned off asp.net core CSRF check.
    var google_csrf_name = "g_csrf_token";
    var cookie = Request.Cookies[google_csrf_name];
    if (cookie == null)
        return StatusCode((int)HttpStatusCode.BadRequest);

    var requestBody = Request.Form[google_csrf_name];
    if (requestBody != cookie)
        return StatusCode((int)HttpStatusCode.BadRequest);

    var idToken = Request.Form["credential"];
    GoogleJsonWebSignature.Payload payload = await GoogleJsonWebSignature.ValidateAsync(idToken).ConfigureAwait(false);

    // Sign-in users
    var provider = GoogleDefaults.AuthenticationScheme;
    var providerKey = payload.Subject;
    var result = await _signInManager.ExternalLoginSignInAsync(provider, providerKey, isPersistent: false, bypassTwoFactor: true).ConfigureAwait(false);
    
if (result.Succeeded)
	return LocalRedirect(ReturnUrl);
    if (result.IsLockedOut)
        return RedirectToPage("./Lockout");
    else
    {
        // If the user does not have an account, then create an account.
	var user = new ApplicationUser { UserName = payload.Email, Email = payload.Email, FirstName = payload.GivenName, LastName = payload.FamilyName, IsEnabled = true, EmailConfirmed = true, DateRegister = DateTime.Now };
	await _userManager.CreateAsync(user).ConfigureAwait(false);
	// Add external Google login
	await _userManager.AddLoginAsync(user, new UserLoginInfo(provider, providerKey, provider)).ConfigureAwait(false);
	// Sign-in the user
        await _signInManager.SignInAsync(user, isPersistent: false).ConfigureAwait(false);

        return LocalRedirect(ReturnUrl);
    }
}

In the above code snippet, ApplicationUserclass is inherited from IdentityUser. Fields _signInManager and _userManager are the instances of Identity SignInManagerand UserManagerrespectively.

Now, the main functions are implemented for Google one tap sign-in.

Hopefully you are now familiar with the main steps required to implement Google One Tag sign-up or sign-in in ASP.NET Core applications. A sample project will be provided later for reference.

asp.net asp.net-core oauth

Join the Discussion

View or add your thoughts below

Comments