Search code examples
c#azure-ad-b2cowin-middleware

How to set TokenValidationParameters.NameClaimType to "username" instead of "name" for Azure AD B2C user?


I have the following code to configure the process of authentication in my ASP.NET MVC web application, including the setting a claim to the user's "name" when validating the user's identity token received by the application.

(Note that I am following this sample code)

public void ConfigureAuth(IAppBuilder app)
{
    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

    app.UseCookieAuthentication(new CookieAuthenticationOptions()
    {
        CookieSecure = CookieSecureOption.Always
    });

    app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
    {
        // Generate the metadata address using the tenant and policy information
        MetadataAddress = String.Format(AadInstance, Tenant, DefaultPolicy),

            // These are standard OpenID Connect parameters, with values pulled from web.config
            ClientId = ClientId,
            Authority = Authority,
            PostLogoutRedirectUri = RedirectUri,
            RedirectUri = RedirectUri,

            Notifications = new OpenIdConnectAuthenticationNotifications()
            {
                RedirectToIdentityProvider = OnRedirectToIdentityProvider,
                AuthenticationFailed = OnAuthenticationFailed,
                AuthorizationCodeReceived = OnAuthorizationCodeReceived,
            },

            // Specify the claims to validate
            TokenValidationParameters = new TokenValidationParameters
            {
                NameClaimType = "name"
            },

            // Specify the scope by appending all of the scopes requested into one string (separated by a blank space)
            Scope = $"{OpenIdConnectScopes.OpenId} {ReadTasksScope} {WriteTasksScope}"
    });
}

The "name" claim type maps to the user's DisplayName, which is returned when I use the code User.Identity.Name.

How can I get User.Identity.Name to map to the user's Username, like in the below screenshot of an Azure Active Directory B2C user?

enter image description here


Solution


  • Here is the 2nd half of the answer above, which includes the code changes that were made:

    1. Add the line of code commented with "Added line here" so that the user's ObjectId is claimed:

      private async Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedNotification notification)
      {
          // Extract the code from the response notification
          var code = notification.Code;
      
          string signedInUserID = notification.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
          TokenCache userTokenCache = new MSALSessionCache(signedInUserID, notification.OwinContext.Environment["System.Web.HttpContextBase"] as HttpContextBase).GetMsalCacheInstance();
          ConfidentialClientApplication cca = new ConfidentialClientApplication(ClientId, Authority, RedirectUri, new ClientCredential(ClientSecret), userTokenCache, null);
      
          ///////////////////////////////////
          // Added line here
          ///////////////////////////////////
          // Add a custom claim to the user's ObjectId ('oid' in the token); Access it with this code: ((System.Security.Claims.ClaimsIdentity)User.Identity).FindFirst("ObjectId").Value
          notification.AuthenticationTicket.Identity.AddClaim(new System.Security.Claims.Claim("ObjectId", signedInUserID));
      
          try
          {
              AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(code, Scopes);
          }
          catch (Exception ex)
          {
              MyLogger.LogTrace("Failed to retrieve AuthenticationResult Token for user " + signedInUserID, MyLogger.LogLevel.Critical);
              return;
          }
      }
      
    2. Then later in the web application, when you need to get and use the user's ObjectId, do this:

      try
      {
          string signedInUserObjectId = ((System.Security.Claims.ClaimsIdentity)User.Identity).FindFirst("ObjectId").Value;
      }
      catch (Exception e)
      {
          ... This should never happen, but better safe than sorry ...
      }
      
    3. And lastly, using the Azure AD graph client, you can get the user object using ObjectId, which contains the user name. The specific query you will need is GET https://graph.windows.net/myorganization/users/{user_id}?api-version. You may need to get the UserPrincipalName or a SignInName, depending on your type of user. For more information, see the "Get a user" section here.