Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Bjorn 7 posts 119 karma points
    Oct 26, 2021 @ 07:25
    Bjorn
    0

    ExternalLogin Azure B2C email claim in Umbraco 9

    Hi there,

    I'm trying to migrate from Umbraco 8.x to 9.0.1. All works fine, except the external backoffice authentication (Azure B2C). In this case I want to login using Azure AD B2C (which currencly has local accounts, and Azure AD. In the future there will be more options).

    The old implementation of the external login was quite different (based on https://24days.in/umbraco-cms/2019/aad-and-headless/umbraco8-aadb2c/)

    I try to simplify this implementation by using the build in external login providers (https://our.umbraco.com/documentation/reference/security/external-login-providers/).

    My current setup let me authenticate against Azure AD B2C. The login works fine. The one thing is that after a succesful login, Umbraco says the email claim is missing:

    Umbraco B2C email claim missing

    The implementation I used came from https://our.umbraco.com/documentation/reference/security/auto-linking/

    I tried to hook into OnAutoLinking and OnExternalLogin, but this seems not to be called yet (https://our.umbraco.com/documentation/reference/security/auto-linking/#transfering-claims-from-external-identities).

    When I take a look at the claims that are returned, I do have an 'emails' claim. I do not have the 'email' claim. I would like to use the value from 'emails' for linking the accounts.

    How can I get this account linking to work?

  • Bjorn 7 posts 119 karma points
    Nov 18, 2021 @ 10:33
    Bjorn
    100

    This specific issue is resolved by adding the claim after the external authentication occurs.

    Remark: this is not in production yet. You might need some null checks for example. Also I'm not sure if this will work for every identity providering configured in your B2C tenant.

        private static Task OnAuthorizationCodeReceived(AuthorizationCodeReceivedContext ctx)
        {
            // This is where we appear after a successfull login, since we use AADB2C Open ID Connect, we already get a lot with the initial authorization code
            ctx.Options.Events.OnAuthorizationCodeReceived = async context =>
            {
                context.ProtocolMessage.RedirectUri = context.ProtocolMessage.RedirectUri.Replace("http:", "https:");
                await Task.FromResult(0);
            };
    
            // Get the current claims
            var claims = ctx.Principal?.Claims;
    
            // Find the original JWT token
            string jwtTokenFromIdentityProvider =
                claims.Where(m => m.Type.Equals("idp_access_token", StringComparison.OrdinalIgnoreCase))
                .Select(m => m.Value).FirstOrDefault();
    
            // Resolve the token to a readable format
            var handler = new JwtSecurityTokenHandler();
            var jsonToken = handler.ReadToken(jwtTokenFromIdentityProvider);
            var tokenFromIdentityProvider = (JwtSecurityToken)jsonToken;
    
            // Get the principal name (so: the login email)
            var principalName = tokenFromIdentityProvider.Claims.First(claim => claim.Type == "upn").Value;
    
            // Define the new claim
            var claimsToAdd = new List<Claim>
            {
                new Claim("email", principalName)
            };
    
            // Add the claim by adding a new ClaimsIdentity
            var appIdentity = new ClaimsIdentity(claimsToAdd);
            ctx.Principal.AddIdentity(appIdentity);
    
            var user = ctx.Principal;
            var identity = user.Identity as ClaimsIdentity;
            var claim = (from c in user.Claims
                         where c.Type == "idp_access_token"
                         select c).Single();
            identity.RemoveClaim(claim);
    
            return Task.CompletedTask;
        }
    
  • Farhan Ali 3 posts 73 karma points
    Oct 12, 2023 @ 08:43
    Farhan Ali
    0

    I had a similar issue, email wasn't set in properties on the user in Active directory / Microsoft Entra ID. So I enabled upn claim in the token configuration. upn claim will contain the email id that was used to login in to Microsoft. Then on OnTokenValidated event I check if the email claim isn't present then simply add upn claim value to email claim like this:

    options.Events = new OpenIdConnectEvents
                                {
                                   OnTokenValidated = context =>
                                   {
                                       var principal = context.Principal;
                                       if (principal is null) throw new InvalidOperationException("No claims found.");
    
                                       // check if email claim doesn't exist and if so, add it from upn claim type
                                       if (!principal.HasClaim(x => x.Type == ClaimTypes.Email))
                                       {
                                           var loggedInEmail = principal.FindFirst(ClaimTypes.Upn)?.Value;
                                           // append loggedInEmail value as a email claim to context principal
                                           if (!string.IsNullOrEmpty(loggedInEmail))
                                           {
                                               var emailClaim = new Claim(ClaimTypes.Email, loggedInEmail);
                                               principal.AddIdentity(new ClaimsIdentity(new[] { emailClaim }));
                                           }
                                       }
    
                                       return Task.CompletedTask;
                                   }
                                };
    

    Don't forget to add upn claim first:

    enter image description here

Please Sign in or register to post replies

Write your reply to:

Draft