(C# ASP.NET Core) SignIn, ReturnUrl and LocalRedirect

This article starts with an explanation of "SignIn", and then explains the various steps for a signin process. Finally, we discuss what is a returnUrl, and what is LocalRedirect, and when should it be used.
(Rev. 19-Mar-2024)

Categories | About |     |  

Parveen,

What is SignIn?

SignIn is used to save information of an authenticated user so that it is available so long as the user is in session. A Remember Me or a persistent cookie can optionally be used to store this information so that it is available on the next visit and the login process can be bypassed.

This information can be used to show his login name on each page, and also to ensure that he is seamlessly able to access all the pages of his "role".

Steps to SignIn

Step 1: Create a collection of Claim items. Each Claim is used to store a single item of data - EMail, Role, etc., In short, this collection stores the information of an authenticated user. The information is typically obtained through a query into some "user" table maintained by the application.

The collection of Claims is used to create a ClaimsIdentity

// Step 1 create a list of claims 

// in the code below (1) UserLogin.EMailID 
// is some property that stores the email. 
// and (2) role is a string variable that stores 
// his role like: String role = "doctor" 
var claims = new List<Claim>
{

  // store email 
  new Claim(ClaimTypes.Email, UserLogin.EMailID),

  // store role 
  new Claim(ClaimTypes.Role, role),

  // store more properties 
};


// create a ClaimsIdentity 
// NOTE: CookieAuthenticationDefaults.AuthenticationScheme is a 
// required, internally defined fixed constant 
var claimsIdentity = new ClaimsIdentity(claims,
    CookieAuthenticationDefaults.AuthenticationScheme);

Step 2: Define the properties of the persistent cookie if the user ticked "Remember Me"

// Step 2 define the expiry and persistence 
// of the cookie 
var authProperties = new AuthenticationProperties
{

  // if the user chose Remember Me 
  IsPersistent = Login.RememberMe

  // expiry of the cookie 
  ExpiresUtc = DateTimeOffset.UtcNow.AddDays(1),
};

Step 3: Use the above objects to perform SignInAsync. This function takes three arguments - (1) the fixed constant CookieAuthenticationDefaults . AuthenticationScheme, (2) ClaimsPrincipal and (3) AuthenticationProperties

// Step 3: signin 
await HttpContext.SignInAsync(
    CookieAuthenticationDefaults.AuthenticationScheme,
    new ClaimsPrincipal(claimsIdentity),
    authProperties);

Video Explanation

Please watch the following youtube video:

The completed code

Usually, the login form is "POSTed" to a function OnPostAsync.

public async Task<IActionResult> OnPostAsync(String returnUrl)
{

  if (!ModelState.IsValid)
  {

    return Page();

  }

  // query the database for user information 
  LoginInfo UserLogin = await . . . ;

  // user exists? 
  if (null == UserLogin)
  {

    ModelState.AddModelError("Login.EMailID", "Account not found.");

    return Page();

  }

  else if (UserLogin.Password != Login.Password)
  {

    ModelState.AddModelError("Login.EMailID", "Wrong password.");

    return Page();

  }

  String role = . . . ? "doctor" : "patient";


  // Step 1 create a list of claims now 
  var claims = new List<Claim>
  {

    // store email 
    new Claim(ClaimTypes.Email, UserLogin.EMailID),

    // store role 
    new Claim(ClaimTypes.Role, role),

    // store more properties 
  };


  // create a ClaimsIdentity 
  // NOTE: CookieAuthenticationDefaults.AuthenticationScheme is a 
  // required, internally defined fixed constant 
  var claimsIdentity = new ClaimsIdentity(claims,
        CookieAuthenticationDefaults.AuthenticationScheme);


  // Step 2 define the expiry and persistence 
  // of the cookie 
  var authProperties = new AuthenticationProperties
  {

    // if the user chose Remember Me 
    IsPersistent = Login.RememberMe

    // expiry of the cookie 
    ExpiresUtc = DateTimeOffset.UtcNow.AddDays(1),
  };


  // Step 3: signin 
  await HttpContext.SignInAsync(
  CookieAuthenticationDefaults.AuthenticationScheme,
      new ClaimsPrincipal(claimsIdentity),
      authProperties);

  // and redirect to his home page 
  // returnUrl is null if the user 
  // comes directly from the login page 
  // in such a case redirect him to his 
  // home page 
  return LocalRedirect(returnUrl ?? $"/--homepage--");

}

What is returnUrl?

If an un-authenticated user tries to access a page, then ASP.NET Core redirects him to the login page - and at the same time stores the returnUrl in a query string parameter.

returnUrl is null if the user comes directly from the login page.

OnPostAsync receives this returnUrl in a parameter and we have to use this parameter to ultimately redirect him to the page he initially intended to see.

What is LocalRedirect?

LocalRedirect is the recommended method for redirection if it is done as a part of SignIn/SignOut process, using a returnUrl.

In other redirects use RedirectToPage(...).


This Blog Post/Article "(C# ASP.NET Core) SignIn, ReturnUrl and LocalRedirect" by Parveen is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.