Support us .Net Basics C# SQL ASP.NET Aarvi MVC Slides C# Programs Subscribe Download

ASP.NET Core google authentication - setting up the UI

Suggested Videos
Part 103 - Custom authorization handler success vs failure | Text | Sldies
Part 104 - External identity providers in asp.net core | Text | Slides
Part 105 - Create google oauth credentials - Client Id and Client Secret | Text | Slides

In this video we will discuss integrating google authentication in asp.net core web application. We will set up the UI (ie. the User Interface) and also configure to redirect the request to Google when Signin with Google button is clicked.

In our next video, we will discuss handling the authenticated user identity received from Google.


We want our login page to look like the following.

asp.net core google authentication


Enable Google Authentication in ASP.NET Core

Include the following configuration in ConfigureServices() method of the Startup class. We discussed registering our application with Google and obtaining Client Id and Secret in our previous video.

services.AddAuthentication().AddGoogle(options =>
    {
        options.ClientId = "XXXXX";
        options.ClientSecret = "YYYYY";
    });

The code required for Google authentication including this AddGoogle() method is present in Microsoft.AspNetCore.Authentication.Google nuget package. Since I am using ASP.NET Core 2.2, this package is automatically included in the project as part of the meta package. If you are using older versions of ASP.NET Core you have to manually install this nuget package.

LoginViewModel

The model for login view is LoginViewModel class. Include ReturnUrl and ExternalLogins properties.

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; }
}

ReturnUrl is the URL the user was trying to access before authentication. We preserve and pass it between requests using 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 etc) that are enabled in our application. You will better understand what this property does in just a bit, when we actually use it.

Login Action in AccountController
  • Populate ReturnUrl and ExternalLogins properties of LoginViewModel and then pass the instance to the view.
  • GetExternalAuthenticationSchemesAsync() method of SignInManager service, returns the list of all configured external identity providers like (Google, Facebook etc).
  • At the moment we only have one external identity provider configured and that is Google.
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> Login(string returnUrl)
{
    LoginViewModel model = new LoginViewModel
    {
        ReturnUrl = returnUrl,
        ExternalLogins = 
        (await signInManager.GetExternalAuthenticationSchemesAsync()).ToList()
    };

    return View(model);
}

Login Page (Login.cshtml)

The following is the code specific to external login.

<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>
  • We are looping through each external login provider we have in Model.ExternalLogins
  • For each external login provider a submit button is dynamically generated
  • At the moment we only have one external identity provider configured and that is Google, so we get one Submit button.
  • This submit button is inside a form. The form method attribute value is post and asp-action attribute value is ExternalLogin
  • So when the submit button is clicked the form is posted to ExternalLogin action in AccountController
  • The login provider is Google, so in the foreach loop, provider.Name returns Google.
  • Since the button name is set to provider, asp.net core model binding maps the provider name which is Google to provider parameter on the ExternalLogin action.
Complete Code of Login View

@model LoginViewModel

@{
    ViewBag.Title = "User Login";
}

<div class="row">
    <div class="col-md-6">
        <h1>Local Account Login</h1>
        <hr />
        <form method="post">
            <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>

ExternalLogin action in AccountController

[AllowAnonymous]
[HttpPost]
public IActionResult ExternalLogin(string provider, string returnUrl)
{
    var redirectUrl = Url.Action("ExternalLoginCallback", "Account",
                        new { ReturnUrl = returnUrl });
    var properties = signInManager
        .ConfigureExternalAuthenticationProperties(provider, redirectUrl);
    return new ChallengeResult(provider, properties);
}

asp.net core tutorial for beginners

8 comments:

  1. InvalidOperationException: No suitable constructor found for entity type 'AuthenticationScheme'. The following constructors had parameters that could not be bound to properties of the entity type: cannot bind 'name', 'displayName', 'handlerType' in 'AuthenticationScheme(string name, string displayName, Type handlerType)'.

    i have this problem can U help.

    ReplyDelete
  2. i got following error
    Oauth token endpoint failure

    how can i solve this problem??

    ReplyDelete
    Replies
    1. you have to made some modification while regestring service in startup.cs
      see this link
      https://github.com/dotnet/aspnetcore/issues/6486

      Delete
  3. I am having error :

    Error 400: redirect_uri_mismatch
    The redirect URI in the request, https://localhost:44342/signin-google, does not match the ones authorized for the OAuth client. To update the authorized redirect URIs, visit: https://console.developers.google.com/apis/credentials/oauthclient/760664201936-qj63s17rb23la88e6nljsri55587a0i4.apps.googleusercontent.com?project=760664201936

    Kindly tell what to do ?

    ReplyDelete
  4. Go to this link:

    https://console.developers.google.com/apis/credentials/oauthclient/760664201936-qj63s17rb23la88e6nljsri55587a0i4.apps.googleusercontent.com?project=760664201936

    look for "Authorized redirect URis"
    1. Click "Add Uri"

    2. An empty textbox will appear

    3. Type "https://localhost:44342/signin-google" into the empty textbox.

    4. Click save.

    ReplyDelete
  5. if (Model.ExternalLogins.Count == 0)

    I get this error when running the application
    Can any one tell me what is the problem?

    ReplyDelete
  6. public async Task Login(string returnUrl)
    {
    //setup login with providers
    LoginVM model = new LoginVM
    {
    ReturnUrl = returnUrl,
    ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList()
    };
    var t = returnUrl;

    ViewBag.newUserSWL = TempData["newUserSWL"] as string;
    return View(model);
    }

    just asking why the return url back with null?
    it's normal?

    ReplyDelete
  7. What is with this "signInManager". It throws error saying "The error signinmanager doesnot exists in the current context"?

    ReplyDelete

It would be great if you can help share these free resources