Search code examples
.netazure-ad-b2croles.net-core-3.1claims

Microsoft.Identity.Web: OnTokenValidated event not triggered


What I'm trying to do is add a claim after authentication. The following example of registering an OnTokenValidation event does not do the trick. The event never triggers.

I'm using Microsoft.Identity.Web to authenticate on Azure AD B2C. That part works! How can I register events using AddMicrosoftIdentityWebAppAuthentication?

services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAdB2C")
    .EnableTokenAcquisitionToCallDownstreamApi(new string[] {Configuration["DemoApi:ServiceScope"]})
    .AddInMemoryTokenCaches();

services.Configure<OpenIdConnectOptions>(AzureADB2CDefaults.OpenIdScheme, options =>
{
    options.Events = new OpenIdConnectEvents
    {
        OnTokenValidated = ctx =>
        {
            //query groups with graph api to get the role

            // add claims
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Role, "superadmin")
            };
            var appIdentity = new ClaimsIdentity(claims);
            ctx.Principal.AddIdentity(appIdentity);
            return Task.CompletedTask;
        },
    };
});

Solution

  • Use MicrosoftIdentityOptions:

    services.Configure<MicrosoftIdentityOptions>(options =>
    {
       options.Events = new OpenIdConnectEvents
       {
          OnTokenValidated = async ctx =>
          { 
             //add claims
             var scopes = Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');
    
             var clientApp = ConfidentialClientApplicationBuilder
                    .Create(Configuration["AzureAD:ClientId"])
                    .WithTenantId(Configuration["AzureAD:TenantId"])
                    .WithClientSecret(Configuration["AzureAD:ClientSecret"])
                    .Build();
             var authResult = await clientApp
                    .AcquireTokenOnBehalfOf(scopes, new UserAssertion(ctx.SecurityToken.RawData))
                    .ExecuteAsync().ConfigureAwait(false);
    
             var graphClient = new GraphServiceClient(Configuration["DownstreamApi:BaseUrl"], new DelegateAuthenticationProvider(
                    requestMessage =>
                    {
                        requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", authResult.AccessToken);
                        return Task.CompletedTask;
                    }));
             var identity = new ClaimsIdentity();
                //https://graph.microsoft.com/1.0/me/transitiveMemberOf/microsoft.graph.group?$count=true&$select=displayName
             var groups = await graphClient.Me.TransitiveMemberOf.Request().Select("displayName").GetAsync().ConfigureAwait(false);
             while (groups != null && groups.Count > 0)
             {
                 foreach (var g in groups)
                 {
                     if (!(g is Group groupItem)) continue;
                     identity.AddClaim(new Claim(ClaimTypes.Role, groupItem.DisplayName));
                 }
                 if (groups.NextPageRequest != null)
                     groups = await groups.NextPageRequest.GetAsync().ConfigureAwait(false);
                 else
                     break;
             }
             ctx.Principal.AddIdentity(identity);
          }
       };
    });
    services.AddMicrosoftIdentityWebAppAuthentication(Configuration);