Add Sign in with Google in Your ASP.NET App: Step-by-step Tutorial

Google Authentication is a secure third-party login provider that you can use in your apps, including ASP.NET applications. Using third-party login providers allows users to use their existing credentials instead of creating yet another username and password combination that they need to remember.

Why Use Third-Party Logins?

There are many reasons why you should add third-party logins to your app (like Google, Facebook, GitHub, etc.), but the top three are:

  • Convenience: Users prefer using their existing credentials instead of having to create and remember separate credentials for every site.
  • Conversion: Since the process is easier, more users are likely to sign up for your app.
  • Security: Google has robust security, allowing you to rely on them and spend your resources on fixing bugs or developing new features instead.

In this article, we are going to talk specifically about adding Google Authentication to an ASP.NET Web Application. There are some steps that we will follow, which are explained in detail in the upcoming sections. These steps are:

  1. Install NuGet package
  2. Update configuration settings in ASP.NET
  3. Create a new Google app
  4. Get application OAuth token
  5. Configure ASP.NET with OAuth
  6. Test

Now, let’s go through each of these steps in detail below.

Setting up Google Authentication in Your .NET Application

The first step here is that we need to install the necessary NuGet package to add Google authentication, which is the Microsoft.AspNetCore.Authentication.Google package. You can install it using the NuGet Package Manager Console or by using the NuGet Package Manager as shown below:

Once installed, this package will give you access to the AddGoogle() method in Program.cs ( or Startup.cs if you are using later versions of ASP.NET). I have navigated to Program.cs and in the services configuration section, I have added the code highlighted below, which adds support for Google authentication. The ClientId and ClientSecret values are empty for now, but we will obtain these values from Google in the next section, store them in the appsettings.json file, and also read them from there.

Since we’ve added the configuration, we need to modify the UI so we can see the button. We are going to show this button in the UI using the Schemes property which is of type IEnumerable<AuthenticationScheme> has been added to the LoginVM. LoginVM is the model of this view which looks like below:

 public class LoginVM
 {
     public string EmailAddress { get; set; }
     public string Password { get; set; }
     public IEnumerable<AuthenticationScheme> Schemes { get; set; }
 }

To get the schemes you can then use the _signInManager.GetExternalAuthenticationSchemesAsync() method like below:

var loginVM = new LoginVM()
{
     Schemes = await _signInManager.GetExternalAuthenticationSchemesAsync()
};

This is going to return list of external authenticaiton schemes that we have configured in the Program.cs, which for now does have only Google.

I have added this code in the Login.cshtml

When this page is rendered, it first checks if any external login providers have been set up. If not, it displays a message indicating the absence of such providers. If there are providers available, it generates a form containing a submit button for each one. The buttons are labeled with the provider’s name and also sets the value attribute to the provider name.

When you click the button, we have defined that we want to call the ExternalLogin action. But, what will this action do?

The ExternalLogin action is responsible for initiating the external login process. When a user selects an external provider for authentication, this action receives the provider’s name as a parameter, constructs a redirect URL for the callback action (ExternalLoginCallback), and generates the properties needed for the external login attempt through the _signInManager.

It then issues a ChallengeResult with the specified provider and properties, which effectively sends the user to the external provider’s login page. This is part of the OAuth authentication flow, where the user will authenticate with the external service, which then redirects back to the application’s callback URL with the authentication result.

If I run the app now, this is what the login page looks like::

This is all we need to do on the ASP.NET Application side for now. It’s time to set up a Google application.

Setting up Google Application

Setting Up a Google Application

Now that we have configured the ASP.NET application side, we need to set up an application in Google Cloud, which will be used for authentication purposes.

First, navigate to https://cloud.google.com

After you log in, you will see the “Console” button at the top-right, which you can click to be redirected to a view where you can create a new project. I have already created a new project from the dropdown highlighted.

Once you create the project, click on the “API & Services” option in the Quick Access section. After navigating to the APIs & Services section, you will see the view below, from which you need to create the application credentials.

To do this, navigate to Credentials > Create Credentials > OAuth client ID. An OAuth client ID is a unique identifier for your application that Google’s OAuth 2.0 authorization system recognizes. It serves as a public ID that Google uses to verify your application’s requests to access Google Cloud resources on behalf of a user.

Once you select this option, you will need to choose the application type, which in our case is going to be a Web Application.

Then, you also need to set the application name, which can be any text you choose.

On the same page, you need to scroll down and define the Authorized Redirect URIs, which will be the local address where the app is running, ending with signin-google. Defining the Authorized Redirect URIs is crucial because it tells Google’s OAuth 2.0 service where it can safely return the authentication response and tokens after a user has authenticated. This ensures that the tokens are sent to the correct application URL

Authorized redirect URIs serve as security measures in the OAuth 2.0 authorization process, particularly when your web application needs access to a user’s Google data. Here’s a simplified breakdown:

  1. Initiating Authorization: Your application redirects the user to Google with:
    • Your OAuth client ID.
    • The data scopes your application is requesting.
    • A redirect URI, which is where Google will send the user after authorization.
  2. User Login & Consent: The user logs into Google and is asked to grant your application permission to access their data.
  3. Crucial Check: If the user agrees, Google issues an authorization code and checks if the provided redirect URI matches one of the authorized redirect URIs pre-configured in your OAuth client settings.

Once you click the “Create” button, a pop-up will appear as shown below:

In this pop-up, you will see the client ID and client secret.

In OAuth 2.0, the “Client ID” and “Client Secret” serve as credentials that represent the client—the application seeking authorization to access user data.

  • Client ID: A public identifier for apps. Although it is publicly accessible, it does not need to be kept secret.
  • Client Secret: A secret known only to the application and the authorization server. It must be kept confidential.

These credentials are used to identify the application making the request to the Google server and are essential in the OAuth 2.0 protocol for obtaining user consent and secure access tokens, which are then used to access protected resources.

Now, we need to store these two values in appsettings.json and access them from there.

Connecting the ASP.NET App with the Google App

Now that we have set up both the ASP.NET application side and the Google application side, we need to configure them to work together. The first step is to store the client ID and client secret values in the appsettings.json file.

I have created a section named “Auth,” and within it, another section named “Google,” which contains the values for ClientID and ClientSecret.

We need to read these values in the AddGoogleAuthentication method, as shown below:

Now, if you run the app, you will see a pop-up prompting you to enter your Google credentials. After entering them, another pop-up will appear, serving as a permission configuration window. Here, you as a user are giving the Shortly App’s Google application permission to access your profile information, such as full name and email address.

But why do we need those? After you log in, for example, you can create a new user profile in the database, or verify the user’s identity with Google. Additionally, you can generate a custom access token from your app. There are countless solutions you can employ. However, to manage all these tasks, you naturally need an additional API endpoint to handle the callback calls.

The Final Step

If the user successfully logs in, you’ll want to be able to retrieve user information, such as full name and email address, within your app. If the user does not exist, you can create a new user and store their details in your application database; if they do exist, you can simply log the user in using the ASP.NET Identity system.

But how does Google know which method or action to call? Well, when we created the ExternalLogin method, we defined the redirectUrl to be ExternalLoginCallback in the Authentication controller. This was then passed as a parameter to the ConfigureExternalAuthenticationProperties method.

Without this method, the application wouldn’t know how to handle users returning from the third-party authentication provider, nor would it be able to complete the sign-in process or manage any errors that might occur.

The final method would look like below:

 public async Task<IActionResult> ExternalLoginCallback(string returnUrl = "", string remoteError = "")
        {

            var loginVM = new LoginVM()
            {
                Schemes = await _signInManager.GetExternalAuthenticationSchemesAsync()
            };

            if (!string.IsNullOrEmpty(remoteError))
            {
                ModelState.AddModelError("", $"Error from extranal login provide: {remoteError}");
                return View("Login", loginVM);
            }

            //Get login info
            var info = await _signInManager.GetExternalLoginInfoAsync();
            if (info == null)
            {
                ModelState.AddModelError("", $"Error from extranal login provide: {remoteError}");
                return View("Login", loginVM);
            }

            var signInResult = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);

            if (signInResult.Succeeded)
                return RedirectToAction("Index", "Home");
            else
            {
                var userEmail = info.Principal.FindFirstValue(ClaimTypes.Email);
                if (!string.IsNullOrEmpty(userEmail))
                {
                    var user = await _userManager.FindByEmailAsync(userEmail);

                    if(user == null)
                    {
                        user = new AppUser()
                        {
                            UserName = userEmail,
                            Email = userEmail,
                            EmailConfirmed = true
                        };

                        await _userManager.CreateAsync(user);
                        await _userManager.AddToRoleAsync(user, Role.User);
                    }

                    await _signInManager.SignInAsync(user, isPersistent: false);

                    return RedirectToAction("Index", "Home");
                }

            }

            ModelState.AddModelError("", $"Something went wrong");
            return View("Login", loginVM);
        }
    }

This method, starts by checking for any errors reported by the provider. If there’s an error, it adds an error message to the model state and returns the user to the login view.

If there are no errors, it attempts to retrieve the login information. If the retrieval fails, it again adds an error message and returns the login view.

Next, it tries to sign in the user with the external login info. If the sign-in succeeds, it redirects the user to the home page. If not, it checks if the user’s email exists in the database. If the email does not exist, it creates a new user account, adds the user to a role, and signs them in. If all these steps succeed, it redirects to the home page. If any step fails during this process, it displays a generic error message and shows the login view again.

Where To Go Next?

For a more detailed explanation and visual walkthrough of the entire process, I invite you to check out our full explanation video on YouTube. This video will guide you step-by-step through the setup and help you understand how to integrate and manage external authentication in your ASP.NET application effectively.

Add Sign in with Google in Your ASP.NET MVC App: Step-by-step Tutorial




Enjoyed this post? Subscribe to my YouTube channel for more great content. Your support is much appreciated. Thank you!


Check out my Udemy profile for more great content and exclusive learning resources! Thank you for your support.
Ervis Trupja - Udemy



Enjoyed this blog post? Share it with your friends and help spread the word! Don't keep all this knowledge to yourself.

Leave a Reply

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