0

TechnicalProfile looks like this:

<TechnicalProfile Id="AAD-Common">
      <DisplayName>Multi-Tenant AAD</DisplayName>
      <Description>Login with your Contoso account</Description>
      <Protocol Name="OpenIdConnect"/>
      <Metadata>
        <Item Key="METADATA">https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration</Item>
        <!-- Update the Client ID below to the Application ID -->
        <Item Key="client_id">[the client id]</Item>
        <Item Key="response_types">id_token</Item>
        <Item Key="scope">openid</Item>
        <Item Key="response_mode">form_post</Item>
        <Item Key="HttpBinding">POST</Item>
        <Item Key="UsePolicyInRedirectUri">false</Item>
        <Item Key="DiscoverMetadataByTokenIssuer">true</Item>

        <!-- The commented key below specifies that users from any tenant can sign-in. Uncomment if you would like anyone with an Azure AD account to be able to sign in. -->
        <Item Key="ValidTokenIssuerPrefixes">https://login.microsoftonline.com/</Item>
      </Metadata>
      <CryptographicKeys>
        <Key Id="client_secret" StorageReferenceId="B2C_1A_AADAppSecret"/>
      </CryptographicKeys>
      <OutputClaims>
        <OutputClaim ClaimTypeReferenceId="issuerUserId" PartnerClaimType="oid"/>
        <OutputClaim ClaimTypeReferenceId="tenantId" PartnerClaimType="tid"/>
        <OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
        <OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="family_name" />
        <OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
        <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="socialIdpAuthentication" AlwaysUseDefaultValue="true" />
        <OutputClaim ClaimTypeReferenceId="identityProvider" PartnerClaimType="iss" />
      </OutputClaims>
      <OutputClaimsTransformations>
        <OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName"/>
        <OutputClaimsTransformation ReferenceId="CreateUserPrincipalName"/>
        <OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId"/>
        <OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId"/>
      </OutputClaimsTransformations>
      <UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin"/>
    </TechnicalProfile>

When I validate this bearer token using Microsoft.AspNetCore.Authentication.JwtBearer AddJwtBearer I get this error:

token: '{"alg":"HS256","typ":"JWT","kid":"TwMsJMU3i_L7zOBKeOw7nWYHov3-eY70IsPfs1gT3aU"}.

{"exp":1588321433,"nbf":1588317833,"ver":"1.0","iss":"https://[mydomain].b2clogin.com/b3d62253-3d6e-453e-bb55-26d87c104a42/v2.0/","sub":"00000000-0000-0000-cdea-6895a0b0757c","aud":"dc3eeaae-c30a-4312-b346-b0919f7d4da1","acr":"b2c_1a_signup_signin","nonce":"defaultNonce","iat":1588317833,"auth_time":1588317833,"tid":"9188040d-6c67-4c5b-b112-36a304b66dad","name":"[my name]","idp":"https://login.microsoftonline.com/[my guid]/v2.0"}'.
Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler: 2020-05-01 17:24:14,518 INFO Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler - JwtB2CBearer was not authenticated. Failure message: IDX10501: Signature validation failed. Unable to match key: 
kid: 'TwMsJMU3i_L7zOBKeOw7nWYHov3-eY70IsPfs1gT3aU'.
Exceptions caught:
 'System.NotSupportedException: IDX10634: Unable to create the SignatureProvider.
Algorithm: 'HS256', SecurityKey: 'Microsoft.IdentityModel.Tokens.RsaSecurityKey, KeyId: 'X5eXk4xyojNFum1kl2Ytv8dlNP4-c57dO6QGTVBwaNk', InternalId: 'e4c64ce7-9e7d-40e2-936a-6658d8f92f07'.'
 is not supported. The list of supported algorithms is available here: https://aka.ms/IdentityModel/supported-algorithms
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateSignatureProvider(SecurityKey key, String algorithm, Boolean willCreateSignatures)
   at Microsoft.IdentityModel.Tokens.CryptoProviderFactory.CreateForVerifying(SecurityKey key, String algorithm)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(Byte[] encodedBytes, Byte[] signature, SecurityKey key, String algorithm, TokenValidationParameters validationParameters)
   at System.IdentityModel.Tokens.Jwt.JwtSecurityTokenHandler.ValidateSignature(String token, TokenValidationParameters validationParameters)
'. 

The Policy Key in Identity Experience Framework is setup using "Manual" configuration and the secret key is something I generated within the Azure AD B2C App.

  • 1
    B2C actually trashes the token from that technical profile since that is just the token from the external IdP. It parses the claims and issues it’s own token. That is configured by the JWTIssuer technical profile and it’s referenced cryptographic keys. Your issue is with the initial setup of policy keys - https://aka.ms/ief. Setup your token signing and encryption keys again. Make sure they are referenced in the JWTIssuer technical profile. – Jas Suri - MSFT May 01 '20 at 08:25
  • Thank you. You were absolutely correct and what you have said made everything make sense in my mind. – Maitland Marshall May 01 '20 at 11:30

1 Answers1

0

I regenerated my tokens as guided here: https://aka.ms/ief Ensured my cryptographic key from original post was set to:

<CryptographicKeys>
    <Key Id="client_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer"/>
</CryptographicKeys>

I also ensured my JwtIssuer within TrustFrameworkBase.xml has its keys set to:

<CryptographicKeys>
    <Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
    <Key Id="issuer_refresh_token_key" StorageReferenceId="B2C_1A_TokenEncryptionKeyContainer" />
 </CryptographicKeys>

It still wouldn't validate, I would get this error:

IDX10501: Signature validation failed. Unable to match keys

Through the guidance of this post: IDX10501: Signature validation failed. Unable to match keys I managed to get it working by setting the IssuerSigningKeys when configuring the JwtBearerOptions:

internal class JwtBearerOptionsConfiguration : IConfigureNamedOptions<JwtBearerOptions>
    {
        private readonly AzureAdB2COptions b2cOptions;
        private readonly IMetaDataFromClaimsPrincipalService metaDataFromClaimsService;

        public JwtBearerOptionsConfiguration(IOptions<AzureAdB2COptions> b2cOptions, IMetaDataFromClaimsPrincipalService metaDataFromClaims)
        {
            this.b2cOptions = b2cOptions.Value;
            this.metaDataFromClaimsService = metaDataFromClaims;
        }

        public void Configure(JwtBearerOptions options)
        {
            this.Configure(Options.DefaultName, options);
        }

        public void Configure(string name, JwtBearerOptions options)
        {
            AzureAdB2COptions currentOptions = this.b2cOptions;

            options.Audience = currentOptions.ClientId;
            options.Authority = currentOptions.BuildAuthority(currentOptions.SignUpSignInPolicyIds.Last());

            options.IncludeErrorDetails = true;

            var configManager = new ConfigurationManager<OpenIdConnectConfiguration>($"{options.Authority}/.well-known/openid-configuration", new OpenIdConnectConfigurationRetriever());
            var openidconfig = configManager.GetConfigurationAsync().Result;

            options.TokenValidationParameters = new TokenValidationParameters
            {
                IssuerSigningKeys = openidconfig.SigningKeys,
                ValidateIssuerSigningKey = true
            };

            options.Events = new JwtBearerEvents
            {
                OnTokenValidated = this.OnTokenValidated,
                OnAuthenticationFailed = this.OnAuthenticationFailed
            };
        }

        private Task OnAuthenticationFailed(AuthenticationFailedContext arg)
        {
            return Task.CompletedTask;
        }

        private Task OnTokenValidated(TokenValidatedContext arg)
        {
            // Check if the authenticated principal has a valid Trust Framework Policy, otherwise do not grant access
            string tfp = this.metaDataFromClaimsService.GetTrustFrameworkPolicy(arg.Principal);

            if (!this.b2cOptions.SignUpSignInPolicyIds.Contains(tfp))
                arg.Fail("Could not validate the Trust Framework Policy");



            return Task.CompletedTask;
        }

    }

Thanks @Jas Suri