Working with authentication in your apps can sometimes be tricky and every app has its own constraints. But the Azure platform provides developers and organizations with many options when it comes to implementing authentication and authorization, from fully customized, coded solutions to turn-key authentication with little to no code changes.
Imagine the scenario where you already have an app that was coded without authentication. This could be an app that was developer to run internally but now it needs to be moved to Azure. To secure access to the app, you have 2 options:
- Add authentication in code so that users can log in with their enterprise credentials
- Use the Azure App Service Authentication option
The first one is more involved. You need to write code, test it and then push the new solution to Azure. It gives you a lot more control but requires code changes. The second option is instant. A few settings within the App Service environment and you're good to go.
At this point, you may wonder why do we need a blog post for App Service Authentication if it works so well. It works great, but it's not perfect for .NET Core 3.1 (yet!). Although the authentication works as expected, due to the differences between .NET and .NET Core, in ASP.NET Core apps the claims principal object doesn't get populated out of the box. That what we have in the official authentication:
At this time, ASP.NET Core does not currently support populating the current user with the Authentication/Authorization feature.
The user authenticates and gets access to the app but my app/code doesn't know who that user user is or what permissions (claims) the user has. A small setback - i know - but this is what I set out to fix with this blog post.
Prerequisites
- An Azure Subscription (get your's FREE here)
- .NET Core 3.1
The ASP.NET Core 3.1 app
I mentioned before that we don't have to do anything to our app to leverage the turn-key Azure App Service Authentication feature. But if we want to use the authenticated user identity to do custom checks, then using the code in this blog will allow you to do so. For this example I'm using Razor Pages but the code should apply to any ASP.NET Core web app.
The main changes in the app are:
- A custom middleware to retrieve the user identity and claims based on the auth header
- A partial page to display a logout option
- A new page to display all the user claims - this is to prove that we have access to the full user object
ASP.NET Core provides a straightforward way to work with its middleware unlike the 'olden days' when OWIN was our only option. With ASP.NET Core, anyone can implement (even me) custom middleware following some basic rules to ensure that the whole pipeline executes as expected. We don't want our middleware to break things. The ASP.NET Core docs do a great job explain how and what we need to implement in our middleware as well as some gotchas.
With that in mind, let's build our middleware that will take the information from the HTTP headers and check if there is an authenticated user before reaching out to Azure AD to grab the user properties
First, lets create a brand new .NET Core Razor pages app using the CLI. Open the shell of your choice and type the following:
dotnet new webapp
Now that we have the app barebones, we can add our custom middlware. You don't really have to, as you can stick your code directly into the Configure()
method in Startup.cs
but this can clatter the code and make it hard to read. Therefore, it is preferable to create a separate class for your middlware code. Let's name it EasyAuthUserValidationMiddleware.cs
and add the following code:
The code looks at the headers, grabs the appropriate information, makes an HTTP call to Azure AD ( to grab the user claims and adds the user to the context so the Context.Current.User
object is populated.
We now need a way to be able to wire up our middleware to the rest of the ASP.NET Core pipeline. For that, we need a few lines of code to expose our middleware and the code below shows how to do it. Create a new class called EasyAuthUserValidationMiddlewareExtensions.cs
and add the following code:
The final step is to configure our app to use our middleware. Open the Startup.cs
class, go to the Configure()
method and add the following line:
app.UseEasyAuthUserValidation();
That's all we need. It's concise and neat and... OK, it should be part of the framework and shouldn't require any extra work on your part but we're working on this. In the meantime, we have a working solution. So let's put our solution to practice.
Enumerate the logged in user claims in the app
Up until this point I didn't have to write any code to implement the authentication. In fact, my app would happily run as is. But I wanted to do a bit more in this example and actually interact with the user object. For this reason, will add a new Razor page, called Claims
where I can enumerate, you guessed it, the user claims - only to show that my middleware is working as expected :)
In the Claims.cshmtl.cs
class, I added the following code to grab the Claims and send them to the view:
public IEnumerable<Claim> UserClaims { get; set; }
public void OnGet()
{
UserClaims = HttpContext.User.Claims;
}
And the in the Claims.cshtml
I added the following code to check if the user is logged in (should always be) and enumerate the user claims on the page:
Running the app locally shouldn't break anything and only show this when going to the Claims page:
Next, we're going to deploy our app to Azure Web Apps and see what happens. Use the method that works best for you: Azure DevOps, GitHub Actions or right-click publish straight from Visual Studio - there I said it :)
Configure Authentication on the Azure Web App.
On the Azure portal, navigate to your web app and open the Authentication tab and flick the switch to On
We will be using Azure AD to configure authentication but as you can see we support a large number of additional providers such as Google, Microsoft Account etc
Select Azure Active Directory and proceed to use the Express settings to set things up. The Create App option will set up an Azure AD App Registration automatically for you when using the Express mode.
If you already have an App Registration that you want to use instead, you can configure this using the Advance mode. Pressing OK will configure the App Registration. There is one more step left to ensure that only logged in users can access our web app. Back in the Authentication tab, we need to select the right option from the drop down (you option will differ based on the Identity Provider you choose)
Since we chose to authenticate with Azure AD, we need to select the Log in with Azure Active Directory option and press Save to apply our changes.
Testing our authentication
You can see our code and Authentication setup in action on the gif below:
Other options
I agree that this may be too involved for your tasting and you may be looking for a simpler solution. How about if I told you there is a Nuget package that can do more or less the same as what I've shown you above. If you're interested, check out Maxime Rouiller's (Microsft CDA and great coder) blog post that explains how his library works and how to get it.
The main difference between mine and Maxime's code is that I check for the authorized user on every request whereas Maxime's library only executes on pages/controllers that have the [Authorize(AuthenticationSchemes = "EasyAuth")]
attribute applied. And maybe his code is nicer :)
Conclusion
Adding authentication doesn't have to be complicated. If you have legacy apps or code that you don't want to update, the Azure App Service offers turn-key authentication using EasyAuth. In this blog post we covered how to set your Azure Web app to Authenticate user and then implement a custom middleware in our ASP.NET Core 3.1 Razor pages web app to retrieve and populate the user object.
I hope this is useful to you and as always, ping me on Twitter if you have any questions!