Build vs Buy: Is Managing Customer Identity Slowing Your Time to Market?Register Now
.NET

Add Authentication to Your ASP.NET Core MVC Application

Learn how to add authentication to your ASP.NET Core MVC Application by using Auth0.

December 14, 2021

ASP.NET Core MVC is a popular framework for building web applications in .NET. It uses the well-known Model-View-Controller design pattern, which helps you achieve separation of concerns for your application UI. In this article, you will learn how to integrate authentication in an ASP.NET Core MVC application by using the Auth0 ASP.NET Core Authentication SDK.

The Sample Application

To focus adding authentication, you will use an existing ASP.NET Core MVC application, which will be described in a moment.

Prerequisites

Before starting, make sure you have the .NET 6 SDK installed on your machine. In fact, the application you are going to modify uses some features of C# 10. To get a quick overview of what's new with .NET 6, check out this article.

Also, this article will use the .NET CLI to build and run the application, but you can use Visual Studio 2022 if you prefer.

Get and run the sample application

You can get the sample application by running the following command in a terminal window:

git clone -b starter --single-branch https://github.com/auth0-blog/acme-aspnet-mvc.git

Once you download it, move to the acme-aspnet-mvc folder and type the following command to launch the application:

dotnet watch

This command will run the sample application and wait for possible changes to the code. If you change the application code, it will be automatically rebuilt.

Note that some specific changes to your code, known as rude edits, may require restarting your application. Read this to learn more.

Now, point your browser to https://localhost:7095. You should get the following page:

ACME website home page

This is the home page of the fictional company ACME Corporation.

By clicking the Catalog link in the header, you can navigate their catalog, which will look as shown below:

ACME catalog

Actually, the Buy now! button is not working. This page is just a placeholder for a page that users would expect to be protected. In other words, only authenticated users should access the catalog page. This is what you are going to implement in the next few sections.

Register with Auth0

Before making any changes, you must register the application with Auth0. You need an Auth0 account, of course. If you don't yet have it, you can sign up for a free one.

Once in the dashboard, move to the Applications section and follow these steps:

  1. Click on Create Application.
  2. Provide a friendly name for your application (for example, ACME Web App) and choose Regular Web Applications as the application type.
  3. Finally, click the Create button.

These steps make Auth0 aware of your ASP.NET Core MVC application and will allow you to control access.

After the application has been created, move to the Settings tab and take note of your Auth0 domain and your client id. Then, in the same form, assign the value https://localhost:7095/callback to the Allowed Callback URLs field and the value https://localhost:7095/ to the Allowed Logout URLs field.

The first value tells Auth0 which URL to call back after the user authentication. The second value tells Auth0 which URL a user should be redirected to after their logout.

Click the Save Changes button to apply them.

Now, head back to the root folder of the sample application project, open the appsettings.json configuration file, and replace its content with the following:

// appsettings.json
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*",
  "Auth0": {
    "Domain": "YOUR_DOMAIN",
    "ClientId": "YOUR_CLIENT_ID"
  }
}

Replace the placeholders YOUR_DOMAIN and YOUR_CLIENT_ID with the respective values taken from the Auth0 dashboard.

Add Authentication

At this point, the basic settings for connecting your application to Auth0 are in place. To add authentication, you need to apply some changes to your application and use those settings. Let's go one step at a time.

Install the Auth0 SDK

As your first step, install the Auth0 ASP.NET Core Authentication SDK by running the following command in your terminal window:

dotnet add package Auth0.AspNetCore.Authentication

The Auth0 ASP.NET Core SDK lets you easily integrate OpenID Connect-based authentication in your app without dealing with all its low-level details.

If you want to learn a bit more, this blog post provides you with an overview of the Auth0 ASP.NET Core SDK.

Set up authentication

Now, let's modify the application code to support authentication. Open the Program.cs file and change its content as follows:

// Program.cs

using Auth0.AspNetCore.Authentication; // 👈 new code

var builder = WebApplication.CreateBuilder(args);

// 👇 new code
builder.Services
    .AddAuth0WebAppAuthentication(options => {
      options.Domain = builder.Configuration["Auth0:Domain"];
      options.ClientId = builder.Configuration["Auth0:ClientId"];
    });
// 👆 new code

// Add services to the container.
builder.Services.AddControllersWithViews();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication(); // 👈 new code
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

Following the highlighted code, you added a reference to the Auth0.AspNetCore.Authentication namespace at the beginning of the file. Then you invoked the AddAuth0WebAppAuthentication() method with the Auth0 domain and client id as arguments. Finally, you called the UseAuthentication() method to enable the authentication middleware.

These changes lay the groundwork for supporting authentication via Auth0.

Implement login

To implement login, add a AccountController.cs file to the Controllers folder with the following content:

// Controllers/AccountController.cs

using Microsoft.AspNetCore.Authentication;
using Auth0.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;

public class AccountController : Controller
{
    public async Task Login(string returnUrl = "/")
    {
        var authenticationProperties = new LoginAuthenticationPropertiesBuilder()
            .WithRedirectUri(returnUrl)
            .Build();

        await HttpContext.ChallengeAsync(Auth0Constants.AuthenticationScheme, authenticationProperties);
    }
}

This class defines a controller meant to handle typical user account operations. In the code above, you implemented the login operation through the Login() method. This method creates a set of authentication properties required for the login and triggers the authentication process via Auth0.

To enable this login operation, you need to change the UI. So, open the _Layout.cshtml file under the Views/Shared folder and update its content as follows:

// Views/Shared/_Layout.cshtml

<!DOCTYPE html>
<html lang="en">
  
<!-- ...existing code -->
  
  <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
    // 👇 new code
    @if (User.Identity.IsAuthenticated)
    {
    // 👆 new code
      <ul class="navbar-nav">
        <li class="nav-item">
          <a class="nav-link text-dark display-6" asp-area="" 
             asp-controller="Catalog" 
             asp-action="Index">Catalog</a>
        </li>
      </ul>
    // 👇 new code
    } else {
      <ul class="navbar-nav ms-auto">
        <li class="nav-item">
          <a class="nav-link text-dark display-6" asp-area="" 
             asp-controller="Account" 
             asp-action="Login">Login</a>
        </li>
      </ul>
      }
      // 👆 new code
  </div>
  
<!-- ...existing code -->

You modify the page's markup by adding a check on the User.Identity.IsAuthenticated property. As you may have figured out, this property lets you know if the current user is authenticated or not. If the user is not authenticated, a Login link will be shown on the right side of the navigation bar.

Test login

Everything is ready. Go to your browser, and you should see the Login link as shown in the following picture:

ACME home page with login

When you click that link, you will be redirected to the Auth0 Universal Login page, as shown in the following screenshot:

Log in with Auth0

The first time the user authenticates, they will be prompted with a page similar to the following:

Consent screen

This page is known as the consent screen, which informs the user that the sample application will access their user profile data. After accepting, you are redirected back to the sample application and should see the Catalog link appearing on the left side of the navigation bar:

ACME home page after login

Congratulations! You added authentication to your ASP.NET Core MVC application!

Leverage Auth0's authentication and authorization services in your .NET applications.

DOWNLOAD THE FREE EBOOK
.NET Identity with Auth0

Protect Private Views

Although you have to authenticate to see the Catalog link in the navigation bar, the catalog view itself is not protected. You can verify this by accessing the https://localhost:7095/Catalog address directly.

You need to restrict access to the catalog only to authenticated users.

Protect the catalog view

For this purpose, edit the CatalogController.cs file under the Controllers folder as shown below:

// Controllers/CatalogController.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization; // 👈 new code

namespace acme.Controllers;

public class CatalogController : Controller {
    private readonly ILogger<HomeController> _logger;

    public CatalogController(ILogger<HomeController> logger)
    {
        _logger = logger;
    }

    [Authorize] // 👈 new code
    public IActionResult Index()
    {
        return View();
    }
}

You added a reference to the Microsoft.AspNetCore.Authorization namespace, which provides you with the Authorize attribute. You use this attribute by attaching it to the Index() method of the controller. This simple change enables the authorization check on the catalog view so that only authenticated users can access it.

Implement logout

Another missing thing to make your application usable is logout. In fact, currently, when you log in to the application, you stay logged in until your session on Auth0 expires. You may want to allow your user to explicitly log out of the application. For this purpose, open the AccountController.cs file in the Controllers folder and add the code highlighted below:

// Controllers/AccountController.cs

using Microsoft.AspNetCore.Authentication;
using Auth0.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization; // 👈 new code
using Microsoft.AspNetCore.Authentication.Cookies; // 👈 new code

public class AccountController : Controller
{
  // ...existing code...
  
  // 👇 new code
  [Authorize]
  public async Task Logout()
  {
    var authenticationProperties = new LogoutAuthenticationPropertiesBuilder()
        .WithRedirectUri(Url.Action("Index", "Home"))
        .Build();

    await HttpContext.SignOutAsync(Auth0Constants.AuthenticationScheme, authenticationProperties);
    await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
  }
  // 👆 new code
}

You added the references to the Microsoft.AspNetCore.Authorization and Microsoft.AspNetCore.Authentication.Cookies namespaces and defined a new method for the AccountController class: Logout(). This method creates a set of required properties and triggers the logout process to destroy both the Auth0 session and the local session.

The next step is to make the logout link available to the user. So, update the content of the _Layout.cshtml file under Views/Shared folder as follows:

// Views/Shared/_Layout.cshtml

<!DOCTYPE html>
<html lang="en">
  
<!-- ...existing code -->
  
  <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
    @if (User.Identity.IsAuthenticated)
    {
      <ul class="navbar-nav">
        <li class="nav-item">
          <a class="nav-link text-dark display-6" asp-area="" 
             asp-controller="Catalog" 
             asp-action="Index">Catalog</a>
        </li>
      </ul>
      // 👇 new code
      <ul class="navbar-nav ms-auto">
        <li class="nav-item">
          <a class="nav-link text-dark display-6" asp-area="" 
             asp-controller="Account" 
             asp-action="Logout">Logout</a>
         </li>
       </ul>
      // 👆 new code
    } else {
      <ul class="navbar-nav ms-auto">
        <li class="nav-item">
          <a class="nav-link text-dark display-6" asp-area="" 
             asp-controller="Account" 
             asp-action="Login">Login</a>
        </li>
      </ul>
      }
  </div>
  
<!-- ...existing code -->

You just added the logout link on the right side of the navigation bar when the user is authenticated. That link points to the Logout() method of the AccountController class.

Test the application

It's time to test this new version of the application. First of all, remove all cookies from your browser or use an incognito window. This is needed because you haven't had a chance to log out so far.

Now, after you log in again, the home page should look as follows:

ACME homepage with logout

When you click the Logout link, you will be disconnected from Auth0 and see the usual home page with only the Login link.

Add a Profile Page

Let's try to go one step further and add a page showing some data about the user.

Specify your scopes

As said before, the Auth0 ASP.NET Core Authentication SDK uses OpenID Connect (OIDC) to authenticate your users. OIDC provides your application with an ID token containing some basic data about the user. From a technical point of view, this user data is available because the SDK requests the openid and profile scopes by default. You don't see this because the SDK takes care of the whole authentication process and manages the ID token. So, by default, you have the user's name and possibly their picture. If you also want the user's email in their profile, you have to specify the scopes explicitly.

Open the Program.cs file and apply the following change:

// Program.cs

// ...existing code...

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddAuth0WebAppAuthentication(options => {
      options.Domain = builder.Configuration["Auth0:Domain"];
      options.ClientId = builder.Configuration["Auth0:ClientId"];
      options.Scope = "openid profile email"; // 👈 new code
    });

// ...existing code...

You assigned a string to the Scope option containing the default scopes mentioned before (openid and profile) and the email scope.

This causes the email to be added to the user profile.

Create the profile model

To show the user profile, let's start by creating a model. Add a UserProfileViewModel.cs file to the Model folder with the following content:

// Model/UserProfileViewModel.cs

namespace acme.ViewModels;

public class UserProfileViewModel
{
  public string EmailAddress { get; set; }

  public string Name { get; set; }

  public string ProfileImage { get; set; }
}

This code simply defines a class with the three elements of the user profile: the name, the email address, and the user's picture.

Create the profile view

To define the associated view, create an Account folder in the Views folder. Then add the Profile.cshtml file to the Views/Account folder with the following content:

@* Views/Account/Profile.cshtml *@

@model acme.ViewModels.UserProfileViewModel
@{
    ViewData["Title"] = "User Profile";
}

<div class="row">
    <div class="col-md-12">
        <div class="row">
            <h2>@ViewData["Title"].</h2>

            <div class="col-md-2">
                <img src="@Model.ProfileImage"
                     alt="" class="img-rounded img-responsive" />
            </div>
            <div class="col-md-4">
                <h3>@Model.Name</h3>
                <p>
                    <i class="glyphicon glyphicon-envelope"></i> @Model.EmailAddress
                </p>
            </div>
        </div>
    </div>
</div>

This markup shows the three properties of the user model.

Create the profile controller

Let's complete the profile by creating the profile controller. Add the following method to the AccountController class:

// Controllers/AccountController.cs

// ...existing code...
using System.Security.Claims;  // 👈 new code
using acme.ViewModels;    // 👈 new code

public class AccountController : Controller
{
  // ...existing code...
  
  // 👇 new code
  [Authorize]
  public IActionResult Profile()
  {
    return View(new UserProfileViewModel()
    {
      Name = User.Identity.Name,
      EmailAddress = User.FindFirst(c => c.Type == ClaimTypes.Email)?.Value,
      ProfileImage = User.FindFirst(c => c.Type == "picture")?.Value
    });
  }
  // 👆 new code
}

You add the references to the System.Security.Claims and acme.ViewModels namespaces and define the Profile() method. This method returns a view based on the user profile model, whose property values are extracted by the currently logged User object. Notice that also the Profile() method is marked with the Authorized attribute.

Finally, let's make the profile page available to the user. Open the _Layout.cshtml file under the Views/Shared folder and update its content as follows:

// Views/Shared/_Layout.cshtml

<!DOCTYPE html>
<html lang="en">
  
<!-- ...existing code -->
  
  <div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
    @if (User.Identity.IsAuthenticated)
    {
      <ul class="navbar-nav">
        <li class="nav-item">
          <a class="nav-link text-dark display-6" asp-area="" 
             asp-controller="Catalog" 
             asp-action="Index">Catalog</a>
        </li>
      </ul>
      <ul class="navbar-nav ms-auto">
        // 👇 new code
        <li class="nav-item">
          <a class="nav-link text-dark display-6" 
             asp-controller="Account" 
             asp-action="Profile">Hello @User.Identity.Name!</a>
        </li>
        // 👆 new code
        <li class="nav-item">
          <a class="nav-link text-dark display-6" asp-area="" 
             asp-controller="Account" 
             asp-action="Logout">Logout</a>
         </li>
       </ul>
    } else {
      <ul class="navbar-nav ms-auto">
        <li class="nav-item">
          <a class="nav-link text-dark display-6" asp-area="" 
             asp-controller="Account" 
             asp-action="Login">Login</a>
        </li>
      </ul>
      }
  </div>
  
<!-- ...existing code -->

You add the link to the profile view next to the logout link. That link will show a welcome message with the user name. Also, it will be shown only when the user is authenticated.

Test the user profile

Go back to your browser and authenticate again. As a first difference, you will notice that you will see the consent screen again. Why? Didn't you previously accept?

Actually, this time, your application is requesting a new piece of information about you: the email. If you compare this screen with the previous one, you will notice this subtle difference.

Consent screen with new the email scope

After you accept that screen, your new home page will look as follows:

ACME-homepage-with-profile-link

You can see the welcome message next to the logout link. If you click the welcome message, the user profile will be shown as in the following picture:

User profile

Summary

Throughout this article, you learned how to integrate authentication in an ASP.NET Core MVC application via Auth0. You've seen how the Auth0 ASP.NET Core Authentication SDK handles OpenID Connect for you under the hood, preventing you from dealing with the technical details. You also learned how to protect the private views of your application and how to implement logout. Finally, you were able to get the user's data to create a user profile page.

You can find the complete code of the ASP.NET Core MVC project in this GitHub repository.

  • Twitter icon
  • LinkedIn icon
  • Faceboook icon