Google Authentication in ASP.NET Core MVC 

Integrating Google Authentication in ASP.NET Core MVC Application

In this article, I will discuss Integrating Google Authentication in ASP.NET Core MVC Applications using ASP.NET Core Identity. Please read our previous article discussing How to Create Google OAuth Credentials. Here, we will set up the UI (i.e., the User Interface) and configure it to redirect the request to Google when the Sign-In with Google button is clicked. We want our login page to look like the following.

Integrating Google Authentication in ASP.NET Core MVC Application

When the user clicks on the Google button, it will open the following page asking the user to log in using his Google credentials as follows:

Integrating Google Authentication in ASP.NET Core MVC Application using ASP.NET Core Identity

Upon successful login, it will make an entry into the AspNetUsers table without a password, as shown in the image below.

Integrating Google Authentication in ASP.NET Core MVC Application using ASP.NET Core Identity

It will also store the provider details in the AspNetUserLogins table, as shown in the below image. The ProviderKey will be unique for each user.

Google Authentication in ASP.NET Core MVC Application

Integrating Google Authentication in ASP.NET Core MVC

Integrating Google Authentication in an ASP.NET Core MVC application using ASP.NET Core Identity involves several steps. This process requires setting up the Google OAuth credentials, as discussed in our previous article and configuring your ASP.NET Core MVC application to use these credentials. Here is a step-by-step guide:

Create Google OAuth Credentials:

As discussed in our previous article, create OAuth 2.0 credentials in the Google Developer Console. Note down the Client ID and Client Secret generated for your application.

Install Necessary NuGet Packages:

Ensure that your ASP.NET Core MVC project has the necessary NuGet packages installed. You would typically need Microsoft.AspNetCore.Identity and Microsoft.AspNetCore.Authentication.Google. We have already installed Microsoft.AspNetCore.Identity package, so please install Microsoft.AspNetCore.Authentication.Google package from NuGet Package Manager Console.

Configure Authentication Services:

In the Program.cs file, configure the authentication services to include Google authentication. You need to use the Client ID and Client Secret obtained from Google.

builder.Services.AddAuthentication()
.AddGoogle(options =>
{
    options.ClientId = "[Your Google Client ID]";
    options.ClientSecret = "[Your Google Client Secret]";
    // You can set other options as needed.
});
Understanding the AddGoogle Method in ASP.NET Core

In ASP.NET Core, the AddGoogle method integrates Google authentication into your web application. This is an extension method for the AuthenticationBuilder class. Its primary purpose is configuring the middleware necessary to authenticate users via their Google accounts.

Purpose of AddGoogle Method
  • OAuth 2.0 Integration: AddGoogle facilitates the integration of the OAuth 2.0 protocol, which is the standard for authorization. Google uses OAuth 2.0 to authenticate users and provide tokens representing their identity and permissions.
  • User Authentication: It allows users to sign into your web application using their Google accounts. This is convenient for users, as it saves them from creating and remembering a separate set of login credentials for your site.
  • Configurable Options: The method allows you to configure various options related to Google authentication, like client ID, client secret, callback paths, scopes for the information you want to access, and more.
How AddGoogle Method Works?

When you call AddGoogle, it registers the Google authentication service with ASP.NET Core’s dependency injection system. This registration tells your application how to handle user sign-ins with Google.

The method requires a Client ID and Client Secret, which you obtain from the Google Developer Console. These credentials are used to establish a trusted connection between your application and Google’s authentication servers.

You can also configure additional options in the AddGoogle method, such as the redirect URI, the path in your application where users will be redirected after successfully authenticating with Google.

LoginViewModel

The model for the login view is the LoginViewModel class. Please include ReturnUrl and ExternalLogins properties in this LoginViewModel class. So, modify the LoginViewModel.cs class file as follows:

using Microsoft.AspNetCore.Authentication;
using System.ComponentModel.DataAnnotations;
namespace ASPNETCoreIdentityDemo.Models
{
    public class LoginViewModel
    {
        [Required]
        [EmailAddress]
        public string Email { get; set; }

        [Required]
        [DataType(DataType.Password)]
        public string Password { get; set; }

        [Display(Name = "Remember Me")]
        public bool RememberMe { get; set; }

        public string? ReturnUrl { get; set; }

        // AuthenticationScheme is in Microsoft.AspNetCore.Authentication namespace
        public IList<AuthenticationScheme>? ExternalLogins { get; set; }
    }
}

Here,

  • ReturnUrl is the URL the user was trying to access before authentication. We preserve and pass it between requests using the ReturnUrl property so the user can be redirected to that URL upon successful authentication.
  • ExternalLogins property stores the list of external logins (like Facebook, Google, Microsoft, Twitter, etc) that are enabled in our application.
What is the AuthenticationScheme Class in ASP.NET Core?

The AuthenticationScheme class in ASP.NET Core is an important part of the authentication system, providing a way to name and configure different authentication methods within an application. It plays an important role in managing how users are authenticated and identified.

The AuthenticationScheme class defines and differentiates between various authentication methods (like cookies, JWT tokens, OAuth, etc.) within an application. Each authentication scheme is associated with a specific authentication handler. An AuthenticationScheme typically consists of a name, a handler type, and an optional display name.

  • Name: A unique identifier for the authentication scheme. This name is used when referring to a specific authentication method.
  • Handler Type: Specifies the type of handler that will process this scheme. Each handler type is responsible for executing specific actions related to authentication (e.g., validating tokens, managing cookies, etc.).
  • Display Name: An optional human-readable name for the scheme, which can be used in user interfaces.
Modifying HttpGet Login Action in AccountController

Populate ReturnUrl and ExternalLogins properties of LoginViewModel and then pass the instance to the view. So, please modify the HttpGet Login Action method of the Account Controller as follows:

[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> Login(string? ReturnUrl = null)
{
    LoginViewModel model = new LoginViewModel
    {
        ReturnUrl = ReturnUrl,
        ExternalLogins = (await signInManager.GetExternalAuthenticationSchemesAsync()).ToList()
    };

    return View(model);
} 
GetExternalAuthenticationSchemesAsync() Method of SignInManager Service:

In ASP.NET Core Identity, the GetExternalAuthenticationSchemesAsync() method of the SignInManager class is used to retrieve a list of all external authentication schemes that have been configured in the application. This method is particularly useful in scenarios where you want to offer users the option to sign in using external identity providers such as Google, Facebook, Twitter, Microsoft, etc.

  • Purpose: Its primary purpose is to obtain information about the external authentication schemes configured in your application.
  • Return Type: The method returns a Task<IEnumerable<AuthenticationScheme>>. Each AuthenticationScheme in the enumeration contains details about an external authentication provider, like its name, display name, etc.
  • Usage: This method is often used in the login view to dynamically generate login buttons or links for each available external authentication provider.

Note: Currently, we only have one external identity provider configured: Google.

Login Page (Login.cshtml)

Modify the Login.cshtml view as follows:

@model LoginViewModel

<div class="row">
    <div class="col-md-6">
        <h1>Local Account Login</h1>
        <hr />
        <form method="post" asp-action="Login" asp-controller="Account">
            <input type="hidden" name="ReturnUrl" value="@Model.ReturnUrl" />
            <div asp-validation-summary="All" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Email"></label>
                <input asp-for="Email" class="form-control" />
                <span asp-validation-for="Email" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Password"></label>
                <input asp-for="Password" class="form-control" />
                <span asp-validation-for="Password" class="text-danger"></span>
            </div>
            <div class="form-group">
                <div class="checkbox">
                    <label asp-for="RememberMe">
                        <input asp-for="RememberMe" />
                        @Html.DisplayNameFor(m => m.RememberMe)
                    </label>
                </div>
            </div>
            <button type="submit" class="btn btn-primary">Login</button>
        </form>
    </div>
    <div class="col-md-6">
        <h1>External Login</h1>
        <hr />
        @{
            if (Model.ExternalLogins?.Count == 0)
            {
                <div>No external logins configured</div>
            }
            else
            {
                <form method="post" asp-action="ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl">
                    <div>
                        @foreach (var provider in Model.ExternalLogins)
                        {
                            <button type="submit" class="btn btn-primary"
                                    name="provider" value="@provider.Name"
                                    title="Log in using your @provider.DisplayName account">
                                @provider.DisplayName
                            </button>
                        }
                    </div>
                </form>
            }
        }
    </div>
</div>

The following is the code specific to external login.

How Does Google OAuth Credentials Work?

Here,

  • We are looping through each external login provider we have in Model.ExternalLogins.
  • For each external login provider, a submit button is dynamically generated.
  • We have only one external identity provider configured, which is Google, so we get one Submit button.
  • This submit button is inside a form. The form method attribute value is post, and the asp-action attribute value is ExternalLogin.
  • So, when the submit button is clicked, the form is posted to ExternalLogin action in Account Controller
  • The login provider is Google, so in the foreach loop, provider.Name returns Google.
HttpPost ExternalLogin Action Method in AccountController

Next, add the following HttpPost ExternalLogin Action Method in the Account Controller. The following ExternalLogin action method will redirect the user to the external login provider sign-in page, in this case, Google. Upon successful authentication, Google redirects the user back to our application, and the ExternalLoginCallback action method will be executed.

[AllowAnonymous]
[HttpPost]
public IActionResult ExternalLogin(string provider, string returnUrl)
{
    //This call will generate a URL that directs to the ExternalLoginCallback action method in the Account controller
    //with a route parameter of ReturnUrl set to the value of returnUrl.
    var redirectUrl = Url.Action(action: "ExternalLoginCallback", controller: "Account", values: new { ReturnUrl = returnUrl });

    // Configure the redirect URL, provider and other properties
    var properties = signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);

    //This will redirect the user to the external provider's login page
    return new ChallengeResult(provider, properties);
}
What is Url.Action() Method in ASP.NET Core?

The Url.Action() method in ASP.NET Core is a helper method used to generate a URL corresponding to an action method on a controller. It’s part of the URL generation API provided by ASP.NET Core and is commonly used in Razor views and controller methods to create URLs dynamically. The Url.Action() method typically takes the following parameters:

  • Action Name: The action method’s name in the controller you want to link to.
  • Controller Name: The controller’s name without the “Controller” suffix. This parameter is optional if the action is within the same controller.
  • Route Values: An object containing the route data. These are additional parameters that the action method might need, like IDs or query strings.
What is the ConfigureExternalAuthenticationProperties Method in ASP.NET Core Identity?

The ConfigureExternalAuthenticationProperties method in ASP.NET Core Identity is an important part of the external authentication process, particularly when integrating third-party authentication providers like Google, Facebook, or Twitter. This method is used to configure the properties of an external authentication provider. Here’s a breakdown of its purpose and functionality:

  • Purpose: The ConfigureExternalAuthenticationProperties method is designed to set up the necessary properties for an external authentication scheme. It’s used when you initiate an external authentication process, providing a way to configure how the external login should behave.
  • Functionality: When a user chooses to log in using an external provider (e.g., by clicking a “Log in with Google” button), your application must redirect the user to the external provider’s login page. The ConfigureExternalAuthenticationProperties method helps set up the redirect information, including where to return after the user has authenticated and any additional parameters required by the external provider.

It typically includes setting the authentication scheme (e.g., “Google”), the redirect URL (the URL to which the external provider should redirect after authentication), and any other specific properties related to the external authentication process.

What is the new ChallengeResult() in ASP.NET Core?

In ASP.NET Core, ChallengeResult is used in the context of authentication, particularly when dealing with external authentication providers like Google, Facebook, or Twitter. It’s a way to initiate the authentication process or “challenge” with an external authentication provider. Here’s a breakdown of what ChallengeResult does and how it’s used:

  • Purpose: ChallengeResult is an action result that triggers the authentication challenge process. When a user attempts to access a resource that requires authentication and is not yet authenticated, the application can return a ChallengeResult to start the authentication process.
  • Working with External Providers: In scenarios where you use external authentication providers, ChallengeResult redirects the user to the external provider’s login page. This is part of the OAuth flow where the user grants permission for the application to access their information from the provider.
ExternalLoginCallback Action Method:

Please add the following ExternalLoginCallback Action Method to the Account Controller. Upon successful authentication, Google redirects the user back to our application, and the following ExternalLoginCallback action is executed. The following method is self-explained, so please go through the comment line.

[AllowAnonymous]
public async Task<IActionResult> ExternalLoginCallback(string? returnUrl, string? remoteError)
{
    returnUrl = returnUrl ?? Url.Content("~/");

    LoginViewModel loginViewModel = new LoginViewModel
    {
        ReturnUrl = returnUrl,
        ExternalLogins = (await signInManager.GetExternalAuthenticationSchemesAsync()).ToList()
    };

    if (remoteError != null)
    {
        ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}");

        return View("Login", loginViewModel);
    }

    // Get the login information about the user from the external login provider
    var info = await signInManager.GetExternalLoginInfoAsync();
    if (info == null)
    {
        ModelState.AddModelError(string.Empty, "Error loading external login information.");

        return View("Login", loginViewModel);
    }

    // If the user already has a login (i.e., if there is a record in AspNetUserLogins table)
    // then sign-in the user with this external login provider
    var signInResult = await signInManager.ExternalLoginSignInAsync(info.LoginProvider,
        info.ProviderKey, isPersistent: false, bypassTwoFactor: true);

    if (signInResult.Succeeded)
    {
        return LocalRedirect(returnUrl);
    }

    // If there is no record in AspNetUserLogins table, the user may not have a local account
    else
    {
        // Get the email claim value
        var email = info.Principal.FindFirstValue(ClaimTypes.Email);

        if (email != null)
        {
            // Create a new user without password if we do not have a user already
            var user = await userManager.FindByEmailAsync(email);

            if (user == null)
            {
                user = new ApplicationUser
                {
                    UserName = info.Principal.FindFirstValue(ClaimTypes.Email),
                    Email = info.Principal.FindFirstValue(ClaimTypes.Email),
                    FirstName = info.Principal.FindFirstValue(ClaimTypes.GivenName),
                    LastName = info.Principal.FindFirstValue(ClaimTypes.Surname),
                };

                //This will create a new user into the AspNetUsers table without password
                await userManager.CreateAsync(user);
            }

            // Add a login (i.e., insert a row for the user in AspNetUserLogins table)
            await userManager.AddLoginAsync(user, info);

            //Then Signin the User
            await signInManager.SignInAsync(user, isPersistent: false);

            return LocalRedirect(returnUrl);
        }

        // If we cannot find the user email we cannot continue
        ViewBag.ErrorTitle = $"Email claim not received from: {info.LoginProvider}";
        ViewBag.ErrorMessage = "Please contact support on info@dotnettutorials.net";

        return View("Error");
    }
}

Now, run the application and check the functionality; it should work as expected.

How Does Google OAuth Credentials Work?

Google OAuth credentials work as part of the OAuth 2.0 protocol, providing a secure and efficient way for applications to access Google services on behalf of a user. Here’s a step-by-step explanation of how it works:

  • User Experience: When a user first interacts with an application that requires access to their Google data, the application requests permission. This is typically done through a user interface provided by Google, ensuring the user’s login credentials are not shared with the application.
  • Application Registration: Before any of this happens, the application developer must register their application with Google. During this registration process, Google provides the application with a client ID and possibly a client secret, which are used to identify the application to Google’s servers.
  • Authentication Request: When the user agrees to grant access, the application sends a request to Google’s OAuth 2.0 server. This request includes the application’s client ID, the scope of access required, and a redirect URI to which Google can send the user after they grant permission.
  • User Consent: Google displays a consent screen to the user, showing the data the application wants to access and asking the user to approve or deny this request.
  • Access Token: If the user grants consent, Google’s OAuth 2.0 server sends an authorization code to the application. The application then exchanges this code for an access token by sending a request to Google, including the authorization code and the application’s client credentials.
  • Accessing Google Services: The application uses this access token to make API requests on behalf of the user. The token tells Google which user the application is acting on behalf of and that the user has given permission for this level of access.
  • Refresh Token: A refresh token might also be provided for long-term access. This token can be used to obtain new access tokens without requiring the user to go through the entire authentication flow again.
  • Security: The user’s Google credentials are not exposed to the third-party application throughout this process. This is a key aspect of OAuth’s security model.

For a better understanding of the above flow, please look at the below image:

How Does Google OAuth Credentials Work?

In the next article, I will discuss Microsoft Account External Login Setup. In this article, I explain Integrating Google Authentication in ASP.NET Core MVC. I hope you enjoy this article, Integrating Google Authentication in ASP.NET Core MVC.

Leave a Reply

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