.netazureazure-active-directoryasp.net-identitymicrosoft-identity-platform

Use Azure AD authentication but manage roles in database in .NET 6


Scenario

I have a platform with multiple smaller applications. Each application needs its own roles, and users may have multiple roles since they might need to access different applications on the platform.

Problem

I have a .NET 6 web API that currently uses application roles on Azure to deal with authorization. It gets very messy since I have to manage multiple Azure groups for each application, e.g., "App 1 Admins", "App 1 Users", "App 2 Admins", "App 2 Users", etc. I want to move the authorization part to the database instead (using something like AspNetRoles). This way, I wouldn't have to create a new group on AD for each role and application and add users to it. Instead, I have a "user management" page where roles are assigned on my own platform.

Currently, I have a working way of adding Azure users and their information to the database using OnTokenValidated. I also created my own Roles table, as well as UserRoles table that maps Azure users in the DB to roles. How can I utilize these roles with the [Authorize(Roles = "App1.Admin, App1.User"] attribute instead of the Azure AD ones? I first thought I could add claims to the user in OnTokenValidated, but then I came across a few resources on this, for example:

Azure AD and Core Idenity Roles Hybrid

Azure AD authentication to existing ASP.NET Core Identity application

Log in with Azure AD and get a UserManager

I use Microsoft Identity like so:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(builder.Configuration, "AzureAd");

I tried following this sample. I made the changes to generate the AspNet tables and added DI, etc. However, my app is still authorizing from Azure AD. Someone also mentioned that an AspNetUser can automatically be created with "CookieSchemeName": "Identity.External" in my appsettings.json under "AzureAd", but nothing gets created.

What is the best move here? I think one option could be to create a custom Authorize attribute that checks the database for the user's roles as well. Is there anything I can do to utilize the normal [Authorize] attribute?


Solution

  • I managed to fix it by utilizing onTokenValidated and injecting custom claims into the context. Works perfectly with the Authorize attribute.