Facebook External Authentication in ASP.NET Core MVC

Integrating Facebook External Authentication in ASP.NET Core MVC

In this article, I will discuss Integrating Facebook External Authentication in ASP.NET Core MVC Application. Please read our previous article discussing Facebook Account External Login Setup. This is a continuation of our previous article, in which we discussed registering our application with Facebook for external authentication and generating the Client ID and Client Secret.

How Does Facebook Account External Login Work?

Facebook Account External Login allows users to sign into other websites, mobile apps, and services using their account credentials. This feature is also known as “Facebook Login” or “Log in with Facebook”. Here’s how it generally works:

  • Integration with Other Services: Many websites and apps integrate Facebook Login to simplify the sign-in process for their users. Instead of creating a new username and password for each site, users can use their Facebook credentials.
  • Convenience: It offers a convenient way for users to access multiple online services without remembering numerous login details. This can streamline the login process, especially on mobile devices.
  • Permission and Data Sharing: When you use Facebook Login, the service usually requests permission to access certain information from your Facebook profile. This might include your name, profile picture, email address, and friend list, depending on the third-party service’s requirements.
  • Security and Privacy Considerations: While this feature offers convenience, it also questions privacy and data sharing. Users should be aware of what information they are sharing and with whom. Facebook provides settings to manage the permissions granted to third-party apps and websites.
  • Implementation by Developers: For app developers and website owners, implementing Facebook Login can increase user sign-ups as it reduces the barriers to new users registering. It uses Facebook’s secure authentication system, which can also enhance the security of the login process.
  • Customization and Control for Users: Users can control which information they share with third-party apps or websites and can revoke access at any time through their Facebook settings.
Facebook External Authentication Login Flow:

Here, we will set up the UI (i.e., the User Interface) and configure it to redirect the request to Facebook when clicking the Sign-In with Facebook button. We want our login page to look like the following. Earlier, we integrated Google and Microsoft, and now we want to integrate Facebook. So, the login page should have Google, Microsoft, and Facebook buttons, as shown in the below image.

Facebook External Authentication Login Flow

When the user clicks on the Facebook button, it will open the following page, asking the user to log in using his Facebook credentials, as shown in the below image.

Integrating Facebook External Authentication in ASP.NET Core MVC

Once you enter your Facebook ID and password, it will open the following page. Please click on the Continue button as shown in the below image.

How Does Facebook Account External Login Work?

Once you click the Continue button, the user will be logged in to your application. On successful login, it will store the user details in the AspNetUsers table without a password, as shown in the image below.

Integrating Facebook External Authentication in ASP.NET Core MVC Application

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.

How to Integrate Facebook External Authentication in ASP.NET Core MVC Application

Integrating Facebook External Authentication in ASP.NET Core MVC

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

Create Facebook OAuth Credentials:

As discussed in our previous article, we registered our Facebook application and created the Client ID and Client Secret.

Install Necessary NuGet Packages:

Ensure that your ASP.NET Core MVC project has the necessary NuGet packages installed. You need to install Microsoft.AspNetCore.Authentication.Facebook package. So please install the Microsoft.AspNetCore.Authentication.Facebook package from NuGet Package Manager.

Configure Authentication Services:

In the Program.cs file, configure the authentication services to include Facebook authentication. You need to use the Client ID and Client Secret obtained from Facebook. We have already configured Google and Microsoft. Let us add the Facebook OAuth authentication.

builder.Services.AddAuthentication()
.AddGoogle(options =>
{
    options.ClientId = "[Your Google Client ID]";
    options.ClientSecret = "[Your Google Client Secret]";
    // You can set other options as needed.
})
.AddMicrosoftAccount(microsoftOptions =>
 {
     microsoftOptions.ClientId = "[Your Microsoft Client ID]";
     microsoftOptions.ClientSecret = "[Your Microsoft Client Secret]";
 })
.AddFacebook(facebookOptions =>
 {
     facebookOptions.ClientId = "[Your Facebook Client ID]";
     facebookOptions.ClientSecret = "[Your Facebook Client Secret]";
 });
What is the AddFacebook Method in ASP.NET Core?

The AddFacebook method in ASP.NET Core is part of the authentication middleware that allows developers to add Facebook-based authentication to their web applications. This method is used within the context of the ASP.NET Core’s Identity framework.

  • Integration with Facebook Login: AddFacebook enables your ASP.NET Core application to authenticate users via their Facebook accounts.
  • OAuth 2.0 Protocol: It uses the OAuth 2.0 protocol, where the application redirects users to Facebook for authentication and receives an access token upon successful login.
  • Configuration: The method typically requires an App ID and Secret, which you get from your Facebook app’s settings in the Facebook Developers portal.
Login View:

We have written the logic in a generic manner, so we aren’t required to change the login view. The page will display the respective button based on the registered external providers. The following is our Login.cshtml view.

@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 onclick="externalLogin(@provider.Name, @Model.ReturnUrl)" 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>
Redirect Request to Microsoft

When clicking the Facebook button, our ASP.NET Core MVC application must redirect the request to Facebook for external authentication. This is done by the ExternalLogin action method of the Account Controller. The code in this method is written in a generic way. So, we don’t need to change the ExternalLogin action method. The following is the ExternalLogin action method of the Account Controller.

[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);
}
Handle External Login Information Received from Facebook

Once Facebook successfully authenticates the user, the request is redirected back to our application, and the following ExternalLoginCallback action method of the Account Controller is executed. The code in this method is also written in a generic way. So, again, we don’t need to make any changes to the ExternalLoginCallback action method. The following is the ExternalLoginCallback action method of the Account Controller.

[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.

In the next article, I will discuss ASP.NET Core Secret Manager. In this article, I explain Integrating Microsoft Authentication in ASP.NET Core MVC. I hope you enjoy this article, Integrating Microsoft Authentication in ASP.NET Core MVC.

Leave a Reply

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