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

ASP.NET Core facebook authentication

Suggested Videos
Part 106 - ASP.NET Core google authentication - Setting up the UI | Text | Slides
Part 107 - ExternalLoginCallback action in asp.net core | Text | Slides
Part 108 - Register application with facebook | Text | Slides

In this video we will discuss, integrating Facebook authentication in asp.net core application.

Integrating external login providers like Google, Facebook, Microsoft etc is similar. So if we know how to integrate one external login providers, integrating others is similar.


We discussed integrating Google authentication in ASP.NET core in our previous videos in this ASP.NET core tutorial.

Enable Google authentication in ASP.NET Core

We configure and enable Google authentication in ConfigureServices() method of Startup class

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication()
        .AddGoogle(options =>
        {
            options.ClientId = "XXXXX";
            options.ClientSecret = "XXXXX";
        });
}

We use  AddGoogle() extension method to configure Google authentication in ASP.NET Core

Enable Facebook authentication in ASP.NET Core

Just like AddGoogle(), we have AddFacebook() extension method to configure Facebook authentication in ASP.NET core.

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication()
        .AddGoogle(options =>
        {
            options.ClientId = "XXXXX";
            options.ClientSecret = "XXXXX";
        })
        .AddFacebook(options =>
        {
            options.AppId = "XXXXX";
            options.AppSecret = "XXXXX";
        });
}

Login View

Since we have both Google and Facebook authentication integrated, we see the respective external login provider button automatically displayed on the Login view.

asp.net core facebook login

@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="Login usin your @provider.DisplayName account">
                                @provider.DisplayName
                            </button>
                        }
                    </div>
                </form>
            }
        }
    </div>
</div>

Redirect request to Facebook

When the Facebook button is clicked, our asp.net core application must redirect the request to Facebook for authentication. This is done by ExternalLogin() action in AccountController. The code in this method is written in a generic way, so it works for both Google and Facebook authentication.

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

Handle External Login Information received from Facebook

After the user is successfully authenticated by Facebook, the request is redirected back to our application, and the following ExternalLoginCallback() action in AccountController is executed. The code in this method is also written in a generic way, so it works for both Google and Facebook authentication.

[AllowAnonymous]
public async Task<IActionResult>
    ExternalLoginCallback(string returnUrl = null, string remoteError = null)
{
    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);
    }

    var info = await signInManager.GetExternalLoginInfoAsync();
    if (info == null)
    {
        ModelState.AddModelError(string.Empty, "Error loading external login information.");

        return View("Login", loginViewModel);
    }

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

    if (signInResult.Succeeded)
    {
        return LocalRedirect(returnUrl);
    }
    else
    {
        var email = info.Principal.FindFirstValue(ClaimTypes.Email);

        if (email != null)
        {
            var user = await userManager.FindByEmailAsync(email);

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

                await userManager.CreateAsync(user);
            }

            await userManager.AddLoginAsync(user, info);
            await signInManager.SignInAsync(user, isPersistent: false);

            return LocalRedirect(returnUrl);
        }

        ViewBag.ErrorTitle = $"Email claim not received from: {info.LoginProvider}";
        ViewBag.ErrorMessage = "Please contact support on Pragim@PragimTech.com";

        return View("Error");
    }
}

Linking external accounts to a local user account

In this example, the user with email (PragimTest@gmail.com) has an account with both Facebook and Google. He can use either of these external accounts to log into our application. 

asp.net core facebook authentication

We want to link both these external accounts (Facebook and Google) to the same local account in our asp.net core application. Local user accounts are in AspNetUsers table and external login accounts are in AspNetUserLogins table.

Notice, for the user with email (PragimTest@gmail.com), there are 2 rows in AspNetUserLogins table. One row is for the Facebook login and the other for Google login. Both these rows link to the one row in AspNetUsers table.

asp.net core identity facebook login

asp.net core tutorial for beginners

2 comments:

  1. If someone has a facebook account created by mobile number not gmail ...the system throw the below exception will not create a record in the asp.netUserLogins table.

    // 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 Mike@test.com";

    please solve it..

    ReplyDelete
  2. signInManager.ConfigureExternalAuthenticationProperties(provider, redirectUrl);

    from where you are geting signInManager ? its giving error

    ReplyDelete

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