Azure AD With ASP.NET Core 2.0

Problem

How to implement Azure AD authentication in ASP.NET Core 2.0

Solution

In previous posts, we have seen how to secure our applications using:

  • Custom login/logout pages using Cookie Authentication.
  • JWT to secure web services.
  • NET Identity to simplify identity and access management.
  • IdentityServer4 to delegate identity and access management to a dedicated application.

In this and the next post, I’ll demonstrate how to use Azure AD to delegate identity and access management to Azure, simplifying our application.

Configure Azure AD

Create Azure subscription (start for free, gives you credit to play).

Create new resource and search for ‘Azure active directory’,

 ASP.NET Core

Create new instance

 ASP.NET Core

Enter details, including the unique ‘initial domain name’, this will become the Tenant Name that will be used in your application; e.g. below the tenant name will be fiverad.onmicrosoft.com,

 ASP.NET Core

Once directory is created, we need to register our application,

 ASP.NET Core

Enter details for your application, including the URL to your application home/sign-in page,

 ASP.NET Core

Once the application is created, you’ll see ‘Application ID’ in the list. This will be used in our application later as ‘Client ID’,

 ASP.NET Core

Click on application and ‘Reply URLs, enter URL where Azure AD will redirect user after authentication (https://localhost:44308/security/signin-callback),

 ASP.NET Core

Next we’ll create a user in Azure AD,

 ASP.NET Core

 ASP.NET Core

Note that username is based on our directory’s domain name i.e. @fiverad.onmicrosoft.com. Also, make a note of the temporary password, you’ll be required to change it on the first login.

 ASP.NET Core  ASP.NET Core

So far you have,

  1. Created Azure AD
  2. Registered your application
  3. Added a user

Next, we’ll setup our application and use Azure AD to authenticate users.

Configure Application

Create an empty project and update Startup to configure services and middleware for MVC and Authentication:

  1. public class Startup  
  2.   {  
  3.       private readonly string TenantName = ""// aka 'Initial Domain Name' in Azure  
  4.       private readonly string ClientId = ""// aka 'Application Id' in Azure  
  5.   
  6.       public void ConfigureServices(IServiceCollection services)  
  7.       {  
  8.           services.AddAuthentication(options =>  
  9.           {  
  10.               options.DefaultAuthenticateScheme =   
  11.                  CookieAuthenticationDefaults.AuthenticationScheme;  
  12.               options.DefaultSignInScheme =   
  13.                  CookieAuthenticationDefaults.AuthenticationScheme;  
  14.               options.DefaultChallengeScheme =   
  15.                  OpenIdConnectDefaults.AuthenticationScheme;  
  16.           }).AddOpenIdConnect(options =>  
  17.           {  
  18.               options.Authority = "https://login.microsoftonline.com/" +   
  19.                                       this.TenantName;  
  20.               options.ClientId = this.ClientId;  
  21.               options.ResponseType = OpenIdConnectResponseType.IdToken;  
  22.               options.CallbackPath = "/security/signin-callback";  
  23.               options.SignedOutRedirectUri = "https://localhost:44308/";  
  24.           }).AddCookie();  
  25.             
  26.           services.AddMvc();  
  27.       }  
  28.   
  29.       public void Configure(IApplicationBuilder app, IHostingEnvironment env)  
  30.       {  
  31.           app.UseAuthentication();  
  32.           app.UseMvcWithDefaultRoute();  
  33.       }  
  34.   } 

Here we are setting up Open ID Connect authentication middleware services with:

  • Authority
    Path to the Azure AD tenant that we’ve setup as authentication server

  • ClientId
    Application identifier that Azure AD provides for our application.

  • ResponseType
    The value that determines authorization flow used and parameters returned from the server. We are interested only in authorization token for now.

  • CallbackPath
    The path where a server will redirect after authentication. We don’t need to create this in our application, the middleware will handle this.

  • SignedOutRedirectUri
    The path where the server will redirect after signing out. This is the path to our application home page, for instance.

Also when configuring authentication middleware, we’ve specified Open ID Connect as challenge scheme. This is the middleware ASP.NET Core will use for users who have not been signed in.

Once signed in, we want to store their identity in a cookie, instead of redirecting to an authentication server for every request. For this reason we’ve added cookie authentication middleware and are using that as default sign-in scheme. If the cookie is missing, users will be ‘challenged’ for their identity.

Add a controller to implement login/logout actions,

  1. public class SecurityController : Controller  
  2.   {  
  3.       public IActionResult Login()  
  4.       {  
  5.           return Challenge(new AuthenticationProperties { RedirectUri = "/" });  
  6.       }  
  7.   
  8.       [HttpPost]  
  9.       public async Task Logout()  
  10.       {  
  11.           await HttpContext.SignOutAsync(  
  12.             CookieAuthenticationDefaults.AuthenticationScheme);  
  13.           await HttpContext.SignOutAsync(  
  14.             OpenIdConnectDefaults.AuthenticationScheme);  
  15.       }  
  16.   }  

When logging out it is important to sign-out from authentication server (Azure AD) and also remove the cookie by signing out from cookie authentication scheme.

Secure controllers (or their actions) using [Authorize] attribute

  1. [Authorize]  
  2. public class HomeController : Controller  
  3. {  
  4.     public IActionResult Index()  
  5.     {  
  6.         return View();  
  7.     }  
  8. }  

Run the application and you’ll be redirected to Azure for authentication.

Source Code

GitHub