Adding claims for roles in a token obtained using MSAL?

124 views Asked by At

I am trying to set up role authorization for our web API controllers so that I can use decorators like [Authorize(Roles="ROLE_ADMIN,ROLE_MANAGER")]. One challenge is that the roles are in custom tables of the application's database. I can connect to the database and successfully add the roles to the claims with the code below. When debugging I can see the roles appended to the Claims. The claim looks like http://schemas.microsoft.com/ws/2008/06/identity/claims/role: ROLE_ADMIN and shows that the issuer is LOCAL_AUTHORITY. I feel like we're on the right track.

builder.Services.Configure<JwtBearerOptions>(JwtBearerDefaults.AuthenticationScheme, options =>
{
    options.Events = new JwtBearerEvents
    {
        OnTokenValidated = async context =>
        {
            var claimsIdentity = context.Principal.Identity as ClaimsIdentity;
            var userEmail = context.Principal.FindFirstValue("preferred_username");

            using var dbContext = new SmpDbContext(new DbContextOptionsBuilder<SmpDbContext>()
                .UseSqlServer(connectionString).Options);

            var appUser = await dbContext.AppUsers.FirstOrDefaultAsync(u => u.Email == userEmail);
            if (appUser != null)
            {
                var roles = await dbContext.Roles.Where(r => r.Users.Contains(appUser)).ToListAsync();

                foreach (var role in roles)
                {
                    claimsIdentity.AddClaim(new System.Security.Claims.Claim(ClaimTypes.Role, role.Authority));
                }
            }
        }
    };
});

However, whenever I call one of the APIs I get the below error. If I comment out the options.Event block the error does not occur. Am I invalidating the token when adding these claims, thus causing Graph and other Azure service using the token to fail? If that is the case, are there any other ways to add the "Roles" within the web api project? I can successfully add policies in builder.Services.AddAuthorization(), but I am hoping to be able to utilize [Authorize(Roles="role1,role2,role3")] instead of resorting to [Authorize(Policy="JustThis")].

Status Code: 0
Microsoft.Graph.ServiceException: Code: generalException
Message: An error occurred sending the request.

 ---> Microsoft.Identity.Web.MicrosoftIdentityWebChallengeUserException: IDW10502: An MsalUiRequiredException was thrown due to a challenge for the user. See https://aka.ms/ms-id-web/ca_incremental-consent. 
 ---> MSAL.NetCore.4.55.0.0.MsalUiRequiredException: 
    ErrorCode: user_null
Microsoft.Identity.Client.MsalUiRequiredException: No account or login hint was passed to the AcquireTokenSilent call. 
   at Microsoft.Identity.Client.Internal.Requests.Silent.SilentRequest.ExecuteAsync(CancellationToken cancellationToken)
   at Microsoft.Identity.Client.Internal.Requests.RequestBase.RunAsync(CancellationToken cancellationToken)
   at Microsoft.Identity.Client.ApiConfig.Executors.ClientApplicationBaseExecutor.ExecuteAsync(AcquireTokenCommonParameters commonParameters, AcquireTokenSilentParameters silentParameters, CancellationToken cancellationToken)
   at Microsoft.Identity.Web.TokenAcquisition.GetAuthenticationResultForWebAppWithAccountFromCacheAsync(IConfidentialClientApplication application, ClaimsPrincipal claimsPrincipal, IEnumerable`1 scopes, String tenantId, MergedOptions mergedOptions, String userFlow, TokenAcquisitionOptions tokenAcquisitionOptions)
   at Microsoft.Identity.Web.TokenAcquisition.GetAuthenticationResultForUserAsync(IEnumerable`1 scopes, String authenticationScheme, String tenantId, String userFlow, ClaimsPrincipal user, TokenAcquisitionOptions tokenAcquisitionOptions)
    StatusCode: 0 
    ResponseBody:  
    Headers: 
   --- End of inner exception stack trace ---
0

There are 0 answers