(C# ASP.NET Core) Social Media based Authentication, Remember Me and Signout

Social media based login provides a neat and user-friendly means of logging into your website. Users are more likely to trust this method because of the level of security provided by various social media platforms. It helps us simplify the sign-in process by delegating many complexities to social media platforms. In this tutorial we present a project that requires a user to login with his google account. Once he logs in, then he is shown his email-id, name and profile picture. We also explain persistence of cookie, i.e., how the user can be remembered, and also the signout scheme.
(Rev. 06-Nov-2022)

Categories | About |     |  

Parveen,

Getting Started with Pre-Requisites

First of all create an OAuth App by following the steps explained in this video - https://youtu.be/55z-SOpiBTE.

Secondly, take note of the nuget package that you will have to add to your ASPNET Core project - Microsoft.AspNetCore.Authentication.Google.


Install-Package Microsoft.AspNetCore.Authentication.Google

This package contains most of the boilerplate code for completing the login process.

Video Explanation (see it happen!)

Please watch the following youtube video:

Login and Profile Pages

I have already created an ASPNET Core project that you can obtain from the downloads attached to this video. So we'll now examine the files and the code written there.

Open the solution explorer and locate the Pages folder. We have two files - the first is the Index.cshtml home page. This file has a link to the second page called Profile. So when the user runs the project he will see this link.


// Index.cshtml file in the Pages folder 
// home page that shows a link 

@page

<h1>Welcome Home!</h1>

<p>
  When you click the link below you will be taken to your 
    google account for authentication.
</p>

<a href="/Profile">Click to Login by Google</a>


Let's have a look at the Profile page. Double-click to open this page.

This page has been marked with the [Authorize] attribute. This means that this is a protected page. When the user tries to open this page he will automatically receive a challenge that will redirect him to the google login page. We'll discuss that code very soon.


// Profile.cshtml file 

@page

@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

@using System.Security.Claims
@using Microsoft.AspNetCore.Authentication
@using Microsoft.AspNetCore.Authentication.Cookies

<h1>You are Logged in!</h1>

<img src="@User?.FindFirstValue(" urn:google:picture")" />

<h3>Name:  @User?.Identity?.Name </h3>

<h3>EMail: @User?.FindFirstValue(ClaimTypes.Email) </h3>

<h3><a  asp-page-handler="SignOut">Sign out</a></h3>


@functions {

  public async Task<IActionResult> OnGetSignOut()
  {

    // kills the login cookie 
    await HttpContext.SignOutAsync(
        CookieAuthenticationDefaults.AuthenticationScheme);

    // redirect to web home or login page 
    return LocalRedirect("/");

  }
}

This page merely displays the google profile picture, then the name of the user as obtained from his google account, and also his email.

There is a signout link also. The code for signout kills the login cookie.

Program.cs file

Lastly, let's now examine the program.cs file. Open the solution explorer and locate the program.cs file. Double click to open it.

You will have to install this nuget package for the code to compile. Then we have the namespaces, and the usual calls to CreateBuilder and AddRazorPages

// Install-Package Microsoft.AspNetCore.Authentication.Google 

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.Google;
using System.Security.Claims;

var builder = WebApplication.CreateBuilder();

builder.Services.AddRazorPages();

builder
    .Services.AddAuthentication(options =>
    {
      options.DefaultScheme = 
        CookieAuthenticationDefaults.AuthenticationScheme;

      options.DefaultChallengeScheme = 
        GoogleDefaults.AuthenticationScheme;
    })
    .AddCookie()
    .AddGoogle(googleOptions =>
    {
      // refer: https://youtu.be/55z-SOpiBTE 
      googleOptions.ClientId = "441---.com";

      googleOptions.ClientSecret = "GO---Xi";

      // get profile pic also 
      googleOptions
        .ClaimActions
        .MapJsonKey("urn:google:picture", "picture", "url");

      googleOptions.AccessDeniedPath = "/";

      googleOptions.Events.OnTicketReceived += (ticket) =>
      {
        // get the email 
        String email = ticket.Principal.FindFirstValue(ClaimTypes.Email);

        // or ticket.Principal.FindFirstValue(ClaimTypes.NameIdentifier) 
        // for a unique id maintained by the social media platform 

        // make a database check if email is registered 
        // suppose we get true after a database query 
        bool isEmailRegistered = true; 

        if (!isEmailRegistered)
        {
          // add to database, if required 

          isEmailRegistered = true;
        }

        // make a database check if email is permitted 
        // by your server 
        String? role = null;

        // make a database check and 
        // query a role to be applied 
        if (isEmailRegistered)
        {

          // suppose we get Admin after database check 
          role = "Admin"; 

          ticket.Principal?.AddIdentity(
            new ClaimsIdentity(new[] { new Claim(ClaimTypes.Role, role) },
            GoogleDefaults.AuthenticationScheme
            ));

        }
        
        // login success! now we can create a persistent 
        // cookie to remember the user for a certain duration 
        if (!String.IsNullOrEmpty(role))
        {
          // remember for 5 minutes or any custom duration 
          if (null != ticket.Properties)
          {
            ticket.Properties.ExpiresUtc = 
                  DateTimeOffset.UtcNow.AddMinutes(5);

            ticket.Properties.IsPersistent = true;
          }
        }
        else
        {
          // access denied if role could not be attached 

          ticket.Response.StatusCode = StatusCodes.Status401Unauthorized;

          // redirect to access denied 
          ticket.ReturnUri = "/AccessDenied";
        }

        return Task.CompletedTask;

      };

    });

builder.Services.AddAuthorization();

var app = builder.Build();

app.UseAuthentication();

app.UseAuthorization();

app.MapRazorPages();

app.Run();

Authentication service is configured next, with the DefaultScheme and DefaultChallengeScheme set to "Cookies" and "Google" exactly as shown.

The call to AddCookie configures various cookie defaults.

The most important settings are done through the AddGoogle extension. The values for ClientId and ClientSecret must match exactly to the ones as shown on your google console page.

MapJsonKey can be used to obtain a url for the profile picture. If you do not add this call, then you will not receive the url to the profile picture.

Lastly, we have subscribed to the TicketReceived event. This event is raised after a user has successfully authenticated from the login page of google.

We can extract the email at this point. Alternatively we could have obtained NameIdentifier which is a unqiue id maintained by social media platforms.

Once you have the email id, then you can process it in whatever manner you like.

You might want to determine if the email exists in your database already. If the user doesn't exist, then you might want to add him and a default profile to your database.

Then you can assign a role to the user. We have assumed that after query, a role called Admin is assigned to the user. Next, this role is added to the ClaimsPrincipal.

Once a role is assigned, the user has been authenticated. We can optionally create a persistent cookie so that the user doesn't have to login very frequently.

If no role could be applied, we can treat the user as not authenticated, so we can redirect him to an access denied page. We haven't added this page to this project - you can add it yourself.

After that we have the usual lines for running the app.

Run the Project

Run the project to open the home page.

See the linked video for a clearer explanation.

Click on the link Click to Login by Google. This link points to the protected profile page. But since we need an authorization, we are redirected to the google login website.

Click on the test email and make a login. Allow the process to complete.

We observe that we reach the protected profile page. User email, name and profile picture, everything appears as expected.

Now click on the sign out link. We observe that we reach the home page again.

Thus we have a working example of google based authentication and authorization. You can similarly implement facebook, twitter and other authentications. Thanks!


This Blog Post/Article "(C# ASP.NET Core) Social Media based Authentication, Remember Me and Signout" by Parveen is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.