I’m working with two .NET 6 projects where one serves as a client app and the other as a server API. Both use MSAL for authentication. The client application is built with Razor pages and makes calls to the server API. I need to implement role-based access control with different permission levels like Administrator and StandardUser. The server uses Bearer token authentication with MSAL web API configuration, while the client uses MSAL web app setup. What’s the proper way to configure both applications in Azure Active Directory and implement the necessary .NET code to support role-based authorization across both apps?
Interesting setup! Are you using the same Azure AD tenant for both apps or splitting them up? Also, how are you handling token refresh when users switch roles? What’s your specific use case and what problems have you hit so far?
The Problem:
You are building a .NET 6 client application (Razor Pages) and a server API, both using MSAL for authentication. You need to implement role-based access control (RBAC) with roles like “Administrator” and “StandardUser” across both applications. The server uses Bearer token authentication with MSAL’s Web API configuration, while the client uses the Web app configuration. The goal is to correctly configure Azure Active Directory and implement the necessary .NET code for RBAC.
Step-by-Step Guide:
Step 1: Register Applications in Azure Active Directory
-
Register the Client Application: In the Azure portal, register your client application as a “Web application”. Carefully configure the “Redirect URIs” to match the URLs of your Razor Pages application.
-
Register the Server API: Register your server API as a “Web API”. Define custom scopes that represent the permissions your API provides. For example, you might have scopes like
api://<your-api-id>/adminandapi://<your-api-id>/standard. These scopes directly reflect the functionality accessible to different roles. -
Grant API Permissions: In the client application’s registration, navigate to “API permissions” and add the permissions for your server API. This step links the client application to the server API, allowing it to request access tokens for the defined scopes. Grant the requested permissions, including
api://<your-api-id>/adminandapi://<your-api-id>/standard.
Step 2: Configure Azure AD App Roles
- Define App Roles: In the server API’s app registration, go to “Manifest” and modify the
appRolessection. Add entries to define your roles: “Administrator” and “StandardUser”. Each role should have a uniqueidandallowedMemberTypes(at leastUser). For example:
"appRoles": [
{
"allowedMemberTypes": [
"User"
],
"description": "Administrator role",
"displayName": "Administrator",
"id": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"isEnabled": true,
"value": "Administrator"
},
{
"allowedMemberTypes": [
"User"
],
"description": "Standard User role",
"displayName": "StandardUser",
"id": "f0e9d8c7-b6a5-4321-9876-543210fedcba",
"isEnabled": true,
"value": "StandardUser"
}
]
- Assign App Roles to Users: Go to “Enterprise Applications”, find your server API, and assign the “Administrator” and “StandardUser” roles to the appropriate users or groups in your Azure AD tenant.
Step 3: Implement .NET Code for Role-Based Authorization
-
Client Application: When requesting tokens, include the necessary scopes in the
scopesparameter. For example:await _authenticationClient.AcquireTokenSilent(scopes, accounts.FirstOrDefault()).ExecuteAsync();. -
Server API: Use the
[Authorize(Roles = "Administrator")]attribute on your API controller actions or methods to restrict access based on the user’s role. The roles will be provided in arolesclaim in the JWT. To handle the roles claim, consider using an authorization middleware that can extract this claim from the validated token and inject it for your API to use.
Understanding the “Why” (The Root Cause):
The core reason this setup is complex is because you’re managing authentication and authorization across two different .NET applications and relying on Azure AD for centralized identity management. This involves careful configuration of both the client application registration (for token acquisition) and the API registration (for role definition and validation). Understanding the difference between app roles (assigned through Azure AD) and scopes (used to request specific permissions) is crucial. The correct combination of scopes, app roles, and attributes in your code is necessary for effective role-based authorization.
Common Pitfalls & What to Check Next:
- Incorrect Scope Configuration: Double-check the scopes in your client application’s token acquisition requests and ensure they align with the scopes defined in your API’s app registration.
- Missing or Incorrect App Role Assignments: Verify that the correct users/groups have been assigned the appropriate app roles in Azure AD.
- Authorization Middleware: Ensure your authorization middleware correctly extracts and uses the
rolesclaim from the JWT. - Incorrect
[Authorize]Attribute Usage: Verify that the[Authorize(Roles = "...")]attribute is placed correctly on your server API methods to restrict access. - Token Expiration: Handle token refresh in your client application to prevent authentication errors caused by expired tokens.
Still running into issues? Share your (sanitized) config files, the exact command you ran, and any other relevant details. The community is here to help!
don’t forget to set up your token validashun params right in startup.cs - i’ve seen tons of peeps mess up the audiense and issuer settings. also check that ur client requests the correct scope w/ AcquireTokenSilent, or u’ll get 401 errors even when the roles r properly assigned.