6 min read

Giving Granular Controls to Azure EasyAuth

Justin Yoo

When working with web applications, implementing authentication and authorization is crucial for security. Traditionally, there have been various ways from simple username/password inputs to OAuth-based approaches. However, implementing authentication and authorization logics can be quite complex and challenging.

Fortunately, Azure offers a feature called EasyAuth, which simplifies this process. EasyAuth is built in Azure PaaS services like App Service, Functions, Container Apps, and Static Web Apps. The best part of using EasyAuth is that you don't have to modify existing code for the EasyAuth integration.

Having said that, since EasyAuth follows one of the cloud architecture patterns – Sidecar pattern, it secures the entire web application. However, fine-tuned control – such as protecting only specific areas or excluding certain parts – can be tricky to achieve.

To address this limitation, the developer community has explored various solutions:

These approaches are still valid today but require updates to align with the latest .NET features.

Throughout this post, I'm going to explore how to transform the authentication token generated by EasyAuth in Azure App Service and Azure Container Apps into a format usable by Blazor and other ASP.NET Core web applications.

Please refer to the previous post about EasyAuth on Azure Static Web Apps.

Download NuGet Package

A few NuGet packages are available for ASP.NET Core web applications to integrate the Client Principal token generated by EasyAuth. Currently, the packages support Microsoft Entra ID and GitHub OAuth.

NOTE: These packages are not the Microsoft official ones. Therefore, use these packages with your own care.

Package Version Downloads
Aliencube.Azure.Extensions.EasyAuth NuGet Version NuGet Downloads
Aliencube.Azure.Extensions.EasyAuth.EntraID NuGet Version NuGet Downloads
Aliencube.Azure.Extensions.EasyAuth.GitHub NuGet Version NuGet Downloads

You can find the source code of these NuGet packages on this GitHub repository.

Getting Started with Azure Developer CLI

The NuGet package repository has sample apps for you to deploy ASP.NET Core web apps to both Azure App Service and Azure Container Apps.

  1. Clone the repository.
  2. Make sure you have the latest version of Azure CLI, Azure Bicep CLI and Azure Developer CLI.
  3. Login to Azure by running the azd auth login command.
  4. Deploy the sample apps by running azd up command. You might be asked to provide both Client ID and Client Secret values of a GitHub OAuth app. If you don't have it, leave them blank.

Apply NuGet Package to Web App

The example uses a Blazor web app, but the same approach applies to any ASP.NET Core web application.

Microsoft Entra ID

  1. Add the NuGet package to your Blazor application.

    dotnet add package Aliencube.Azure.Extensions.EasyAuth.EntraID

    NOTE: At the time of writing, it's still in preview. Therefore, use the --prerelease tag at the end of the command like dotnet add package Aliencube.Azure.Extensions.EasyAuth.EntraID --prerelease.

  2. Open the Program.cs file and find the code line, var app = builder.Build();. Then, add dependencies for authentication and authorisation.

    // 👇👇👇 Add dependencies for authentication/authorisation
    builder.Services.AddAuthentication(EasyAuthAuthenticationScheme.Name)
                    .AddAzureEasyAuthHandler<EntraIDEasyAuthAuthenticationHandler>();
    builder.Services.AddAuthorization();
    // 👆👆👆 Add dependencies for authentication/authorisation
    
    var app = builder.Build();
  3. In the same Program.cs file and find the code line, app.Run();. Then activate authentication and authorisation.

    // 👇👇👇 Activate authentication/authorisation
    app.UseAuthentication();
    app.UseAuthorization();
    // 👆👆👆 Activate authentication/authorisation
    
    app.Run();
  4. Apply the Authorize attribute to a specific page component.

    @page "/random-page-url"
    
    @* 👇👇👇 Apply authorisation *@
    @using Aliencube.Azure.Extensions.EasyAuth
    @using Microsoft.AspNetCore.Authorization
    
    @attribute [Authorize(AuthenticationSchemes = EasyAuthAuthenticationScheme.Name)]
    @* 👆👆👆 Apply authorisation *@
  5. Deploy the app to either Azure App Service or Azure Container Apps.
  6. After deployment, configure the authentication settings like:

    Authentication Settings - Azure Container Apps Authentication Settings - Azure App Service

  7. Open your web browser and navigate the page component you applied authorisation, and see the 401 (Unauthorized) error.
  8. Sign into the web app through /.auth/login/aad and visite the page again, and verify you're able to see the content on that page.

GitHub OAuth

It's mostly the same as using Microsoft Entra ID, except using a different NuGet package.

  1. Install the GitHub-specific NuGet package.

    dotnet add package Aliencube.Azure.Extensions.EasyAuth.GitHub

    NOTE: At the time of writing, it's still in preview. Therefore, use the --prerelease tag at the end of the command like dotnet add package Aliencube.Azure.Extensions.EasyAuth.GitHub --prerelease.

  2. Open the Program.cs file and find the code line, var app = builder.Build();. Then, add dependencies for authentication and authorisation. Make sure this time you use GitHubEasyAuthAuthenticationHandler instead of EntraIDEasyAuthAuthenticationHandler.

    // 👇👇👇 Add dependencies for authentication/authorisation
    builder.Services.AddAuthentication(EasyAuthAuthenticationScheme.Name)
                    .AddAzureEasyAuthHandler<GitHubEasyAuthAuthenticationHandler>();
    builder.Services.AddAuthorization();
    // 👆👆👆 Add dependencies for authentication/authorisation
    
    var app = builder.Build();
  3. Follow the same steps as above.

How Does It Work?

When authenticated through Azure EasyAuth, a request header X-MS-CLIENT-PRINCIPAL is created. It contains a base-64 encoded JSON object, which needs to be decoded and transformed into a ClaimsPrincipal instance for role-based access control.

Here's the JSON object. For brevity, most claims are omitted except two. Here's the JSON object generated from Microsoft Entra ID authentication.

{
  "auth_typ": "aad",
  "name_typ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
  "role_typ": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
  "claims": [
    {
      "typ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress",
      "val": "john.doe@contoso.com"
    },
    {
      "typ": "roles",
      "val": "User"
    }
  ]
}

And, here's the JSON object generated from GitHub authentication.

{
  "auth_typ": "github",
  "name_typ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
  "role_typ": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
  "claims": [
    {
      "typ": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name",
      "val": "John Doe"
    },
    {
      "typ": "urn:github:type",
      "val": "User"
    }
  ]
}

This JSON object should be converted into the ClaimsPrincipal instance for granular control on each page.

Let's understand the JSON object.

  • auth_typ: It indicates the authentication method currently used. For example, Microsoft Entra ID says aad and GitHub says github.
  • name_typ: After the authentication, the claim with this key is bound to HttpContext.User.Identity.Name.
  • role_typ: They claim key for authorisation by roles.
  • claims: A collection of claims generated by either Microsoft Entra ID or GitHub.

But the challenge on the X-MS-CLIENT-PRINCIPAL token is that it has no role claims matching to the role_typ key. The Entra ID one contains the roles claim and GitHub one contains the urn:github:type claim, which is not following the OpenID Connect standard, while ClaimsPrincipal object on ASP.NET Core web apps do follow the standard. The NuGet packages above convert the role values.

By adding and activating the conversion handler, users are now able to login to the web app with EasyAuth and access to certain pages with proper permissions. Here's the example that uses the AuthenticationSchemes property to let users access to pages as long as they sign in with EasyAuth.

@page "/random-page-url"

@attribute [Authorize(AuthenticationSchemes = EasyAuthAuthenticationScheme.Name)]

This is another example that uses the Roles property to let users having the User permission to access to the given page.

@page "/random-page-url"

@attribute [Authorize(Roles = "User")]

NOTE: Make sure that X-MS-CLIENT-PRINCIPAL token from Microsoft Entra ID doesn't contain the roles claims out-of-the-box because it really depends on each tenant's policy.

Roadmap

Azure EasyAuth supports multiple identity providers, but the NuGet packages currently support Microsoft Entra ID and GitHub OAuth.

  • ✅ Microsoft Entra ID
  • ✅ GitHub
  • ⏹️ OpenID Connect
  • ⏹️ Google
  • ⏹️ Facebook
  • ⏹️ X
  • ⏹️ Apple

Contributions are always welcome!


So far, we've walked through how to transform Azure EasyAuth authentication token to the ClaimsPrincipal object to be used within ASP.NET Core web apps. With these packages, you can control individual pages based on the users' role and increase apps' security with less efforts.

Learn More

For further details on Azure EasyAuth, check out: