Using Auth0 to control Authentication in .Net Core 2.2

Auth0 provides universal authentication and authorization for your application, you can see more about them here.

I've used Auth0 a few times and always found it a really good fit for authentication. There can be a lot of coding to make your app connect to all the different providers but Auth0 takes a good chunk of the work out of it.

I wanted to get into using Auth0 with a new .net core 2.2 web app I have been working on.

This post is part of a series where I will add Auth0 to a .net core 2.2 application. Wire it into my user management and look at how to customise Auth0 interface and the options they provide. So lets get going.

Auth0 Setup

I am assuming you are already up and running on Auth0 and have setup an account.

Once your in and running on Auth0 you need to create an "Application" This will give you the details and the settings you need to connect and authenticate.

Auth0 Application settings

More docs from Auth0 are here

In the Application Settings you need to set the Callback URL : for me it's https://localhost:44309/callback

Auth0 Callback

Adding to .Net Core 2.2

Source Code can be found here

To make Auth0 with with .net Core we need the packages for cookies and option Id Connect from nuget.

Install-Package Microsoft.AspNetCore.Authentication.Cookies
Install-Package Microsoft.AspNetCore.Authentication.OpenIdConnect

We start in the Startup.cs file

Our configureservices will look something like this

    public void ConfigureServices(IServiceCollection services)
    {
      services.Configure<CookiePolicyOptions>(options =>
      {
        // This lambda determines whether user consent for non-essential cookies is needed for a given request.
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
      });

      // Add authentication services
      services.AddAuthentication(options =>
        {
          options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
          options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
          options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        })
        .AddCookie()
        .AddOpenIdConnect("Auth0", options =>
        {
          // Set the authority to your Auth0 domain
          options.Authority = $"AUTH0 - Domain";

          // Configure the Auth0 Client ID and Client Secret
          options.ClientId = "AUTH0 - ClientID";
          options.ClientSecret = "AUTH0 - Client Secret";

          // Set response type to code
          options.ResponseType = "code";

          // Configure the scope
          options.Scope.Clear();
          options.Scope.Add("openid");

          // Set the callback path, so Auth0 will call back to http://localhost:3000/callback
          // Also ensure that you have added the URL as an Allowed Callback URL in your Auth0 dashboard
          options.CallbackPath = new PathString("/callback");

          // Configure the Claims Issuer to be Auth0
          options.ClaimsIssuer = "Auth0";
          options.Events = new OpenIdConnectEvents
          {
            OnRedirectToIdentityProvider = context =>
            {
              context.ProtocolMessage.SetParameter("audience", "AUTH0 - API ID");

              return Task.FromResult(0);
            }
          };

          options.Events = new OpenIdConnectEvents
          {
            // handle the logout redirection
            OnRedirectToIdentityProviderForSignOut = (context) =>
            {
              var logoutUri =
                $"https://AUTH0-DOMAIN/v2/logout?client_id=AUTH0CLIENTID";

              var postLogoutUri = context.Properties.RedirectUri;
              if (!string.IsNullOrEmpty(postLogoutUri))
              {
                if (postLogoutUri.StartsWith("/"))
                {
                  // transform to absolute
                  var request = context.Request;
                  postLogoutUri = request.Scheme + "://" + request.Host + request.PathBase + postLogoutUri;
                }

                logoutUri += $"&returnTo={Uri.EscapeDataString(postLogoutUri)}";
              }

              context.Response.Redirect(logoutUri);
              context.HandleResponse();

              return Task.CompletedTask;
            }
          };
        });

      services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

Yep that's a whole lot of code so lets look at what it is doing.

The code in here for Auth0

      // Add authentication services
      services.AddAuthentication(options =>
        {
          options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
          options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
          options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        })
        .AddCookie()
        .AddOpenIdConnect("Auth0", options =>
        {
          // Set the authority to your Auth0 domain
          options.Authority = $"AUTH0 - Domain";

          // Configure the Auth0 Client ID and Client Secret
          options.ClientId = "AUTH0 - ClientID";
          options.ClientSecret = "AUTH0 - Client Secret";

          // Set response type to code
          options.ResponseType = "code";

          // Configure the scope
          options.Scope.Clear();
          options.Scope.Add("openid");

          // Set the callback path, so Auth0 will call back to http://localhost:3000/callback
          // Also ensure that you have added the URL as an Allowed Callback URL in your Auth0 dashboard
          options.CallbackPath = new PathString("/callback");

          // Configure the Claims Issuer to be Auth0
          options.ClaimsIssuer = "Auth0";
          options.Events = new OpenIdConnectEvents
          {
            OnRedirectToIdentityProvider = context =>
            {
              context.ProtocolMessage.SetParameter("audience", "AUTH0 - API ID");

              return Task.FromResult(0);
            }
          };

          options.Events = new OpenIdConnectEvents
          {
            // handle the logout redirection
            OnRedirectToIdentityProviderForSignOut = (context) =>
            {
              var logoutUri =
                $"https://AUTH0-DOMAIN/v2/logout?client_id=AUTH0-CLIENTID";

              var postLogoutUri = context.Properties.RedirectUri;
              if (!string.IsNullOrEmpty(postLogoutUri))
              {
                if (postLogoutUri.StartsWith("/"))
                {
                  // transform to absolute
                  var request = context.Request;
                  postLogoutUri = request.Scheme + "://" + request.Host + request.PathBase + postLogoutUri;
                }

                logoutUri += $"&returnTo={Uri.EscapeDataString(postLogoutUri)}";
              }

              context.Response.Redirect(logoutUri);
              context.HandleResponse();

              return Task.CompletedTask;
            }
          };
        });

Between the CookiePolicyOptions and the

  services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

ConfigureServices

Lets get into the code for Auth0

services.AddAuthentication(options =>
        {
          options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
          options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
          options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        })
        .AddCookie()
        .AddOpenIdConnect("Auth0", options =>
        {

Now we're starting to add Auth0 to our project, we start off by setting the Authentication and sign in options. These are telling what openID can use in our project.

We set it to using the Cookie. And then we add OpenID with Auth0 and get into the setup of Auth0.

.AddOpenIdConnect("Auth0", options =>
{
          // Set the authority to your Auth0 domain
          options.Authority = $"https://AUTH0 - Domain";

          // Configure the Auth0 Client ID and Client Secret
          options.ClientId = "AUTH0 - ClientID";
          options.ClientSecret = "AUTH0 - Client Secret";

          // Set response type to code
          options.ResponseType = "code";

          // Configure the scope
          options.Scope.Clear();
          options.Scope.Add("openid");
      
          options.CallbackPath = new PathString("/callback");

          // Configure the Claims Issuer to be Auth0
          options.ClaimsIssuer = "Auth0";
  • AUTH0 - Domain - This is the Domain you setup in Auth0
  • AUTH0 - ClientID - This is the client ID of your application in Auth0
  • AUTH0 - Client Secret - This is the Client Secret from your application in Auth0
Auth0 Application settings

The above code configures Auth0 and OpenID to work.

Now we need to setup our events.

      options.Events = new OpenIdConnectEvents
      {
        OnRedirectToIdentityProvider = context =>
        {
          context.ProtocolMessage.SetParameter("audience", "AUTH0 - API ID");

          return Task.FromResult(0);
        }
      };

Next we set up our events. These events decide how our app will work. This is for the connect event we can get information back from Auth0 and the provider the user used.

  • AUTH0 - API ID - This comes from in Auth0 the API options.
Auth0 API Settings

      options.Events = new OpenIdConnectEvents
      {
        // handle the logout redirection
        OnRedirectToIdentityProviderForSignOut = (context) =>
        {
          var logoutUri =
            $"https://AUTH0-DOMAIN/v2/logout?client_id=AUTH0-CLIENTID";

          var postLogoutUri = context.Properties.RedirectUri;
          if (!string.IsNullOrEmpty(postLogoutUri))
          {
            if (postLogoutUri.StartsWith("/"))
            {
              // transform to absolute
              var request = context.Request;
              postLogoutUri = request.Scheme + "://" + request.Host + request.PathBase + postLogoutUri;
            }

            logoutUri += $"&returnTo={Uri.EscapeDataString(postLogoutUri)}";
          }

          context.Response.Redirect(logoutUri);
          context.HandleResponse();

          return Task.CompletedTask;
        }
      };

Our Logout event. These handles the log out and ending of the user session in the application. Release and clear and then redirect back to our default logout page.

Configure

Next we move to the configure method of our Startup.cs and add the

  app.UseAuthentication();

This will tell our applcation we are to use some form of Authentication.

Login / Logout

Now that we have configured our application to use authentication and to use open ID we need to add our login option. We can do this anywhere I've created a new controller called "AccountController" added two methods Login and logout to the controller.



  using System.Threading.Tasks;
  using Microsoft.AspNetCore.Authorization;
  using Microsoft.AspNetCore.Mvc;
  using Microsoft.AspNetCore.Authentication;
  using Microsoft.AspNetCore.Authentication.Cookies;

  public class AccountController : Controller
  {
    public async Task Login(string returnUrl = "/")
    {
      await HttpContext.ChallengeAsync("Auth0", new AuthenticationProperties() { RedirectUri = returnUrl });
    }

    [Authorize]
    public async Task Logout()
    {
      await HttpContext.SignOutAsync("Auth0", new AuthenticationProperties
      {
        // Indicate here where Auth0 should redirect the user after a logout.
        // Note that the resulting absolute Uri must be whitelisted in the
        // **Allowed Logout URLs** settings for the app.
        RedirectUri = Url.Action("Index", "Home")
      });
      await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
    }
  }

Then I just add a button to the home page with "~/account/login" and when I click Login I get the Auth0 Login page.

Auth0 Login page

Summary

It can always feel a bit intimidating trying to work with Authentication in any application. Even Auth0 can feel abit heavy but once you start into it. It's very simple and powerful and gives us a real great way to expand and grow our application.

I've covered the basic setup in this post. It's part of a series. My goal is to create a .net core 2.2 web application that uses Auth0 to handle the login and signup of users. In other posts in this series I'll go into more detail on different parts.