Authentication in ASP .NET Core
Tags: dotnet, tutorial, csharp, webdev
Published: 2022-02-01 00:51:19

---
title: Authentication in ASP .NET Core
published: true
description: How you can authenticate users in .NET Core
tags: dotnet, tutorial, csharp, webdev
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7pqj4e91c8mcsfdsjlo4.jpg
---

> This article covers authentication in ASP .NET Core. It tries to explain the concepts and how they relate and also shows some code so you can hopefully add authentication to your own .NET app.

Authenticating a user means determining a user's identity. We do this to ensure they are who they say they are. Once we ensure we trust them, we can log them into our app and show them resources that only logged in users should have access to.

## Main scenarios

Here's the main scenarios we're looking to address:

- Authenticating a user.
- Responding when an unauthenticated user tries to access a restricted resource.

## Handlers, services to handle the authentication flows

![Setting up authentication](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/y0kp425ll6pg7wgj61gb.png)

To carry out an authentication flow, you need a handler. You can have more than one handler, but it must implement the `IAuthenticationService` interface. The handler/s is used by the authentication middleware. The registered authentication handlers and their configuration options are called "schemes".

### A scheme

To use a scheme, you need to _register_ it here `Startup.ConfigureServices`, i.e. like so:

```csharp
void ConfigureServices() 
{
  // register your scheme
}
```

What you need to do is to first call `AddAuthentication()` followed by a call to a specific scheme, like the below example:

```csharp
void ConfigureServices() 
{
  services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddJwtBearer(JwtBearerDefaults.AuthenticationScheme, options =>   Configuration.Bind("JwtSettings", options))
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => Configuration.Bind("CookieSettings", options));
}
```

Here we call `AddAuthentication()` followed by a call to both the schemes `AddJwtBearer()` and `AddCookie()`. By calling these schemes, you register them and their config settings.

> You don't always need to explicitly call `AddAuthentication()`, if you use ASP .NET Identity, that call is done internally for you.

## Set up middleware

To understand why we do this step, lets first talk about the request pipeline. Imagine the following scenario:

> The calling client makes a request towards a resource on your system. To allow for that to happen, they need to be logged in to your system. To log in, the user needs to provide credentials (typically username and password) that convinces us they are who they say they are. We call this to _authenticate_. However, we need to write code to ensure the request is intercepted and we have a chance to validate the user. This is why we now need to talk to middleware and configure it to use the handlers/schemes we registered thus far with ASP .NET.

Now we go to another method `Configure()` in our `Startup` class and call `UseAuthentication()` like so:

```csharp
void Configure() 
{
  UseAuthentication();
}
``` 

> You need to call `UseAuthentication()` in the right time so anything dependent on the auth can use it. Here's som guidelines:
> 
> - After `UseRouting()`, so that route information is available for authentication decisions.
> - Before `UseEndpoints()`, so that users are authenticated before accessing the endpoints.

## Authenticating the user

![Authenticating the user](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gkdcyzp6303msd1we6us.png)

Ok, so you've seen two parts of three so far:

1. Register scheme/handler
1. Instructing the pipeline to use it
1. Authenticating the user  **<- to be explained**

Let's discuss how to authenticate the user. We will do that by borrowing some code from a sample project that does Cookie authentication [Cookie authentication](https://github.com/dotnet/aspnetcore/blob/main/src/Security/samples/Cookies/Controllers/AccountController.cs)

### Register scheme/handler

First, let's check 1) the registering of the scheme, in `ConfigureServices()` method in _Startup.cs_:

```csharp
public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        services.AddAuthentication(CookieScheme) // Sets the default scheme to cookies
            .AddCookie(CookieScheme, options =>
            {
                options.AccessDeniedPath = "/account/denied";
                options.LoginPath = "/account/login";
            });

        // Example of how to customize a particular instance of cookie options and
        // is able to also use other services.
        services.AddSingleton<IConfigureOptions<CookieAuthenticationOptions>, ConfigureMyCookie>();
    }
```

Note the call to `AddCookie()` for registering the scheme and the config `AccessDeniedPath` and `LoginPath`. By specifying those config values, we know what route to send the user to if they are:

- unable to provide credentials `/account/denied`
- a place to provide credentials and be logged in `/account/login`

### Configure middleware

We've registered the scheme and is ready to use it. Our next step is explicitly telling our app to use it by a call to `UseAuthentication()`.

```csharp
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
    }

    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}
```

Note the call to `app.UseAuthentication()` and how it's _after_ the call to `UseRouting()`, so we have the routing information, and _before_ the call to `UseEndpoints()` so the latter can leverage the authentication capability.

### Doing the actual authentication

When we registered the scheme, we told it where to go for logins, i.e `/account/login`, that's a controller class and method we need to write. So, create a `AccountController.cs` with the following content:

```csharp
using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;

namespace AuthSamples.Cookies.Controllers;

public class AccountController : Controller
{
}
``` 

What we need to fill this class with is the following:

- a way to render a login form
- a method that handles a user sending their login credentials and have those validated
- a method for handling logging out

**Rendering a login form**

Here we our controller code becomes simple, like so:

```csharp
[HttpGet]
public IActionResult Login(string returnUrl = null)
{
    ViewData["ReturnUrl"] = returnUrl;
    return View();
}
```

It becomes simple as there's a template that we render _Login.cshtml_:

```html
<h2>Login</h2>

<div class="row">
    <div class="col-md-8">
        <section>
            <form asp-controller="Account" asp-action="Login" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal" role="form">
                <div class="form-group">
                    <label class="col-md-2 control-label">User</label>
                    <div class="col-md-10">
                        <input type="text" name="username" />
                    </div>
                </div>

                <div class="form-group">
                    <label class="col-md-2 control-label">Password</label>
                    <div class="col-md-10">
                        <input type="password" name="password" />
                    </div>
                </div>

                <div class="form-group">
                    <div class="col-md-offset-2 col-md-10">
                        <button type="submit" class="btn btn-default">Log in</button>
                    </div>
                </div>
            </form>
        </section>
    </div>
</div>
```

The above template consists of a username field, a password field and submit button.

**Handling login request**

Imagine now the user enters their credentials in the above form, then we need controller code to handle that:

```csharp
private bool ValidateLogin(string userName, string password)
{
    // For this sample, all logins are successful.
    return true;
}

[HttpPost]
public async Task<IActionResult> Login(string userName, string password, string returnUrl = null)
{
    ViewData["ReturnUrl"] = returnUrl;

    // Normally Identity handles sign in, but you can do it directly
    if (ValidateLogin(userName, password))
    {
        var claims = new List<Claim>
            {
                new Claim("user", userName),
                new Claim("role", "Member")
            };

        await HttpContext.SignInAsync(new ClaimsPrincipal(new ClaimsIdentity(claims, "Cookies", "user", "role")));

        if (Url.IsLocalUrl(returnUrl))
        {
            return Redirect(returnUrl);
        }
        else
        {
            return Redirect("/");
        }
    }

    return View();
}
```

- the `Login()` method being called via a POST request when the user hits the login button. We are provided with `username` and `password` and we call `ValidateLogin()` (here you typically want a call to a database to validate the user, ensure they exist, the password is correct etc).  
- Then we sign in the user, if `ValidateLogin()` responds with true. 
- The sign in happens when we call `HttpContext.SignInAsync()`. Said method needs a `ClaimsPrincipal` instance to be created. That object needs a `ClaimsIdentity` object as an instance. High-level we say who the user is and can later determine what parts of the system the user shall have access to, in an _authorization_ process. 

**Handle logout request**

The user might want to logout, to handle that, you can add another method to your `AccountController` class like so:

```csharp
public async Task<IActionResult> Logout()
{
    await HttpContext.SignOutAsync();
    return Redirect("/");
}
```

Calling `HttpContext.SignOutAsync()` will ensure that the app forgets all about you and your login session.

What goes on here is that:

### Routing the user correctly

At this point you are wondering, how does the system know how to send the users to this login form, like how do I check who's logged in or not?

This is when we have a look at the _HomeController.cs_ file. It uses an attribute class `Authorize` to force the user to the login page if they are not authenticated. Here's how that would work:

1. User tries to go to route `/Home/MyClaims`

   ```csharp
   [Authorize]
   public IActionResult MyClaims()
   {
      return View();
   }
   ``` 

2. If the user is logged in, then they are presented with the view represented by `MyClaims` function. If not logged in, then they are taken to `account/login`.

## Summary

Hopefully, you now have a good starting point for understanding how to authenticate and login a user to an ASP .NET application. In the next part we will look at how you can _authorize_ a user, i.e determine what user should have access to what resources.