This article purpose is to describe how to secure your ASP.NET Framework application using OWIN middleware and Microsoft Entra ID (Azure AD) authentication. This comprehensive guide walks you through creating protected endpoints while maintaining public health checks for load balancers.
Requirements
- Visual Studio 2022
- Azure Subscription
Walkthrough
Creating the App Service
Within our Azure subscription, we will create an App Service of type Web App.
In the template, we will fill in basic data:
- Select our Azure subscription
- Create a resource group if one doesn't already exist
- Give our application a name
- We will publish the code directly from Visual Studio 2022
- Our Runtime will be ASP.NET V4.8
- Choose the Region and plan that best suits our needs
- For this example, we will select a less crowded region and proceed with the Free plan
Proceed with the "Review + Create" option.
Configuring the Default Domain
After our service has been created, we will navigate to the dashboard and copy the "Default Domain" value.
Registering the Application in Microsoft Entra ID
Now we will navigate within our Azure Portal to Microsoft Entra ID > Manage > App Registrations.
Within this window, we will register the application by clicking the "New Registration" option.
In this window, we will:
- Register the name of our application
- Define which Tenants can access the application
- Register the URI by copying the App Service application URL as "Web"
Configuring Authentication
After having our application registered, in the same dashboard of our registered application, we navigate to Manage > Authentication.
In this window, we will activate the following options:
- ID tokens (used for implicit and hybrid flows)
- Access tokens (used for implicit and hybrid flows)
Creating the Application in Visual Studio 2022
We will create a new project with the following template:
- ASP.NET Web Application (.NET Framework)
- Select runtime: .NET Framework 4.8
In the next window:
- Select type: MVC
- Authentication: None (because Azure will handle the authentication)
- Uncheck "Configure for HTTPS"
Installing Required Dependencies
Now we will proceed to install the necessary dependencies to run the project. Within the project:
Right-click > Manage NuGet Packages for Solution
Search for and install the following packages:
- Microsoft.Owin.Security.OpenIdConnect
- Microsoft.Owin.Security.Cookies
- Microsoft.Owin.Host.SystemWeb
- Microsoft.IdentityModel.Protocols.OpenIdConnect
Modifying Web.Config
After installing our dependencies, we start by modifying the Web.Config file.
Within appSettings, we proceed to modify the following values.
From Microsoft Entra ID, in App registrations, we look for our application and copy the following values:
- ClientID
- TenantID
- RedirectUri (that we configured in App Service)
<appSettings>
<add key="webpages:Version" value="3.0.0.0" />
<add key="webpages:Enabled" value="false" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
<add key="ida:ClientId" value="<your-client-id>" />
<add key="ida:Authority" value="https://login.microsoftonline.com/<your-tenant-id>/v2.0" />
<add key="ida:RedirectUri" value="https://<your-application>.azurewebsites.net/" />
</appSettings>
<system.web>
<authentication mode="None" />
<compilation debug="true" targetFramework="4.8" />
<httpRuntime targetFramework="4.8" />
<customErrors mode="Off"/>
</system.web>
Creating Startup.cs
Now we will proceed with the creation of a file in the root called Startup.cs. What this file does is basically provide authentication control that sits in front of all requests.
using Microsoft.Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using Owin;
using System.Configuration;
[assembly: OwinStartup(typeof(TestAuthApplication.Startup))]
namespace TestAuthApplication
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = ConfigurationManager.AppSettings["ida:ClientId"],
Authority = ConfigurationManager.AppSettings["ida:Authority"],
RedirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"],
ResponseType = "code id_token",
Scope = "openid profile email",
TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
ValidateIssuer = false
}
});
}
}
}
Creating Controllers
Now we proceed to create two controllers: a health check which will allow us to return a 200 response to the load balancer without needing authentication, and a protected page.
HealthCheckController.cs (No Authentication Required)
Within Controllers > HealthCheckController.cs:
using System;
using System.Web.Mvc;
namespace TestAuthApplication.Controllers
{
[AllowAnonymous]
public class HealthCheckController : Controller
{
public ActionResult Index()
{
return Json(new
{
status = "healthy",
timestamp = DateTime.UtcNow,
service = "TestAuthApplication"
}, JsonRequestBehavior.AllowGet);
}
public ActionResult Ping()
{
return Content("OK");
}
}
}
To prevent authentication, we define [AllowAnonymous]
.
ProtectedController.cs (Authentication Required)
Now we will proceed to create a protected page in Controllers > ProtectedController.cs:
using System.Web.Mvc;
namespace TestAuthApplication.Controllers
{
[Authorize]
public class ProtectedController : Controller
{
public ActionResult Index()
{
ViewBag.UserName = User.Identity.Name;
return View();
}
public ActionResult SecureData()
{
return Json(new
{
message = "This is protected data",
user = User.Identity.Name
}, JsonRequestBehavior.AllowGet);
}
}
}
To require authentication, we define [Authorize]
.
Creating the View
Additionally, we can add a view for this in Views > Protected > Index.cshtml:
@{
ViewBag.Title = "Protected Page";
}
<h2>Protected Page - Authentication Successful!</h2>
<p>Welcome, @User.Identity.Name!</p>
<p>You are successfully authenticated.</p>
<p>This page requires authentication to access.</p>
Publishing to Azure
With our project ready, we will now proceed to publish it:
- Right-click on the project > Publish > Azure
- Authenticate with the user account that has access to our Azure subscription
- Select our resource group and app service
- Click Publish
Testing the Application
Finally, we verify the access:
- Page without authentication requirement
Health check endpoint should return 200 without login
- User authenticated in the tenant
Successfully accesses protected pages
- User authenticated but not in the tenant
Receives access denied message
Summary
Public endpoints (health check) that don't require authentication
Protected endpoints that require Azure AD authentication
OWIN middleware handling the authentication flow
Integration with Azure App Service for hosting
Top comments (0)