Getting email after logged in with Azure AD on Azure AD B2C - azure-active-directory

Scenario: I'm using Angular 5 for front-end and .NET core 2.0 for back-end, MSAL.js to authenticate against Azure AD B2C in Angular SPA, then use returned id_token as Bearer Token to send requests to WebAPI endpoints.
I have successfully setup multi-tenant Azure AD as a provider in Azure AD B2C (followed the answer here Multi-tenant Azure AD in Azure AD B2C), but in the returned id_token, there's no claim for email address. Note: If I configure single-tenant Azure AD, I get back a claim with type http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress for email address, but wasn't able to do so with multi-tenant AD.
I believe the limitation is with Azure AD v2.0 that's been mentioned here: https://learn.microsoft.com/en-us/azure/active-directory/develop/active-directory-v2-limitations
Question: How do I retrieve the user's email address after log in.
I followed the guideline in this article https://monteledwards.com/2017/10/18/a-complete-integration-azure-ad-b2c-azure-ad-graph-api-logic-apps/ to add an extra logic app to resolve email from id_token, but my problem is I don't have objectId back either.
Claims I've got back after successful authentication are:
iss - https://login.microsoftonline.com/<My-B2C-Tenant-Id>/v2.0/
exp - ticks
nbf - ticks
aud - My-B2C-App-Id
name - string
http://schemas.microsoft.com/identity/claims/identityprovider - tid
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier - My-B2C-App-Id
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname - string
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname - string
nonce - GUID
http://schemas.microsoft.com/identity/claims/scope - User.Read
azp - GUID
ver - 1.0
iat - ticks
My technical profile for multi-tenant Azure AD -> Azure AD B2C is:
<TechnicalProfile Id="AzureADAccountProfile">
<DisplayName>Log in with your work account</DisplayName>
<Protocol Name="OpenIdConnect"/>
<OutputTokenFormat>JWT</OutputTokenFormat>
<Metadata>
<Item Key="authorization_endpoint">https://login.microsoftonline.com/common/oauth2/v2.0/authorize</Item>
<Item Key="client_id">My ID</Item>
<Item Key="DiscoverMetadataByTokenIssuer">true</Item>
<Item Key="HttpBinding">POST</Item>
<Item Key="IdTokenAudience">My ID</Item>
<Item Key="response_types">id_token</Item>
<Item Key="scope">openid profile</Item>
<Item Key="UsePolicyInRedirectUri">false</Item>
<Item Key="ValidTokenIssuerPrefixes">https://login.microsoftonline.com/</Item>
</Metadata>
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_AzureADSecret"/>
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="enterpriseAuthentication" />
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="name" />
<OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="tid" />
<OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="oid" />
<OutputClaim ClaimTypeReferenceId="tenantId" PartnerClaimType="tid"/>
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="unique_name" />
<OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="given_name" />
<OutputClaim ClaimTypeReferenceId="surName" PartnerClaimType="family_name" />
<OutputClaim ClaimTypeReferenceId="tenant" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName"/>
<OutputClaimsTransformation ReferenceId="CreateUserPrincipalName"/>
<OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId"/>
</OutputClaimsTransformations>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>

Getting the email address that is associated with the user account differs between a consumer/personal account and an organization/work account.
Personal account
Reference: Azure Active Directory v2.0 tokens reference
The email address that is associated with the user account can be issued in the ID token.
1) Change the "scope" metadata item from "openid profile" to "openid profile email".
<Metadata>
<Item Key="scope">openid profile email</Item>
</Metadata>
2) Change the "email" output claim from:
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="unique_name" />
to:
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
Work account
The email address that is associated with the user account must be retrieved using the Microsoft Graph API.
1) Change the "AzureADAccountProfile" technical profile from "OpenIdConnect" to "OAuth2" and add the metadata items to retrieve the profile properties for the signed-in user.
Note: The "Get a user" operation doesn't return the tenant identifier of the signed-in user so the following technical profile creates the "identityProvider" claim, which is required for the alternative security identifier, from the domain part of the "userPrincipalName" property of this user.
<TechnicalProfile Id="AzureADAccountProfile">
<DisplayName>Log in with your work account</DisplayName>
<Protocol Name="OAuth2"/>
<OutputTokenFormat>JWT</OutputTokenFormat>
<Metadata>
<Item Key="AccessTokenEndpoint">https://login.microsoftonline.com/organizations/oauth2/v2.0/token</Item>
<Item Key="authorization_endpoint">https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize</Item>
<Item Key="BearerTokenTransmissionMethod">AuthorizationHeader</Item>
<Item Key="ClaimsEndpoint">https://graph.microsoft.com/v1.0/me</Item>
<Item Key="client_id"><!-- Enter your client ID --></Item>
<Item Key="DiscoverMetadataByTokenIssuer">true</Item>
<Item Key="HttpBinding">POST</Item>
<Item Key="IdTokenAudience"><!-- Enter your client ID --></Item>
<Item Key="response_types">code</Item>
<Item Key="scope">https://graph.microsoft.com/user.read</Item>
<Item Key="UsePolicyInRedirectUri">false</Item>
<Item Key="ValidTokenIssuerPrefixes">https://login.microsoftonline.com/</Item>
</Metadata>
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_AzureADSecret"/>
</CryptographicKeys>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="enterpriseAuthentication" />
<OutputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="displayName" />
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="mail" />
<OutputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" PartnerClaimType="surname" />
<OutputClaim ClaimTypeReferenceId="socialIdpUserId" PartnerClaimType="id" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" PartnerClaimType="userPrincipalName" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CreateAzureADIdentityProvider" />
<OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
<OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
<OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
</OutputClaimsTransformations>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
2) Create the "CreateAzureADIdentityProvider" claims transformation.
<ClaimsTransformation Id="CreateAzureADIdentityProvider" TransformationMethod="ParseDomain">
<InputClaims>
<InputClaim ClaimTypeReferenceId="userPrincipalName" TransformationClaimType="emailAddress" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="identityProvider" TransformationClaimType="domain" />
</OutputClaims>
</ClaimsTransformation>

Related

How to get custom B2C policy to send a oauth2 bearer (token) to my custom SignUp/SignIn API

I am trying to have my custom B2C policy to communicate with my custom SignUp/SignIn API and authenticate via oauth2 bearer (not static bearer). I have followed the instructions found here: 1 (to the letter) but unable to get it working. I cannot get the custom policy to send the Authorization header with a bearer token to my API, unsure why.
Here is my configuration:
<ClaimsProvider>
<DisplayName>REST APIs</DisplayName>
<TechnicalProfiles>
<!--OAUTH2.0 customization START-->
<TechnicalProfile Id="REST-AcquireAccessToken">
<DisplayName></DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">https://login.microsoftonline.com/mytenant.onmicrosoft.com/oauth2/v2.0/token</Item>
<Item Key="AuthenticationType">Basic</Item>
<Item Key="SendClaimsIn">Form</Item>
</Metadata>
<CryptographicKeys>
<Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_SecureRESTClientId" />
<Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_SecureRESTClientSecret" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="client_credentials" />
<InputClaim ClaimTypeReferenceId="scope" DefaultValue="https://graph.microsoft.com/.default" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="bearerToken" PartnerClaimType="access_token" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
<!--OAUTH2.0 customization END-->
<TechnicalProfile Id="REST-GetProfile">
<DisplayName>Get user extended profile Azure Function web hook</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<!-- Set the ServiceUrl with your own REST API endpoint -->
<Item Key="ServiceUrl">https://url_to_API/api/SignIn?</Item>
<Item Key="SendClaimsIn">Body</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="UseClaimAsBearerToken">bearerToken</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
</Metadata>
<InputClaims>
<!-- Claims sent to your REST API -->
<InputClaim ClaimTypeReferenceId="bearerToken"/>
<InputClaim ClaimTypeReferenceId="objectId" />
<InputClaim ClaimTypeReferenceId="extension_MemberId" />
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<OutputClaims>
<!-- Claims parsed from your REST API -->
<OutputClaim ClaimTypeReferenceId="extension_MemberId" PartnerClaimType="extension_MemberId"/>
<OutputClaim ClaimTypeReferenceId="email" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
Something that was not mentioned in the documentation, but saw on a post, is you need to add an orchestration step in the signup/signin journey to call the "get an access token" - but not 100% sure it needs it.
<OrchestrationStep Order="5" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="RESTGetAccessToken" TechnicalProfileReferenceId="REST-AcquireAccessToken" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="6" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="RESTGetProfile" TechnicalProfileReferenceId="REST-GetProfile" />
</ClaimsExchanges>
</OrchestrationStep>
I checked my API without Authorization configured and can see the custom B2C policy is calling it, but I can't see any evidence of a bearer token at all (looked at the Request.Headers in the c# code). Also, I am unsure how to configure my API Authorization side of things, that was also omitted in the documentation (unfortunately).
With the above, am I missing something? Should I see the Authorization header with a bearer token?
Any help is very much appreciated!

how to get OAuth2 bearer access token in b2c custom policy to send claims to My REST API during signin sign up custom policy

i have b2c local account sign in sign up flow using custom policies to sign in sign up
i want to add a call to my secure web API to send user claims to this API. i have followed this documentation Secure your API and access through custom policy and using OAuth2 bearer authentication. for this i have registered another application as the above documentation says, but i am not getting any bearer token in bearer token claim(access token).
i am getting this following specific error(in jwt.ms) when running my policy
error:Claim "bearerToken" specified for the bearer token is not present in the available claims.
but when i add the Technical profile "REST-AcquireAccessToken" in user journey i can see it is returning the access token in bearerToken Claim.
but when i add Technical Profile "REST-API-SignUp" in user journey i got the following error :
do i need to call both the REST technical profiles (REST-AcquireAccessToken,REST-API-SignUp) in user journey steps??
i tried doing so but it faild to upload the policy.
any help will be much appreciated.
these are the Technical Profiles i used first for acquiring the Access Token and second one to call API to send user claims
<TechnicalProfile Id="REST-AcquireAccessToken">
<DisplayName></DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">https://login.microsoftonline.com/MyTenantName.onmicrosoft.com/oauth2/v2.0/token</Item>
<Item Key="AuthenticationType">Basic</Item>
<Item Key="SendClaimsIn">Form</Item>
</Metadata>
<Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_SecureRESTClientId" />
<Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_SecureRESTClientSecret" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="client_credentials" />
<InputClaim ClaimTypeReferenceId="scope" DefaultValue="https://MyTenantName.onmicrosoft.com/api/.default" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="bearerToken" PartnerClaimType="access_token" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
<!--talking To API-->
<TechnicalProfile Id="REST-API-SignUp">
<DisplayName>Send account details to API</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<!-- Set the ServiceUrl with My REST API endpoint -->
<Item Key="ServiceUrl">https://My API endPoint URL</Item>
<Item Key="SendClaimsIn">Body</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="UseClaimAsBearerToken">bearerToken</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
</Metadata>
<InputClaims>
<!-- Claims Needs to sent to My REST API -->
<InputClaim ClaimTypeReferenceId="bearerToken" />
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="givenName" />
<InputClaim ClaimTypeReferenceId="surname" />
<InputClaim ClaimTypeReferenceId="displayName" />
</InputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
In user Journey i am calling the Technical Profile "REST-API-SignUp" in step 8 like this:
<OrchestrationStep Order="8" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="RESTPostUserClaims" TechnicalProfileReferenceId="REST-API-SignUp" />
</ClaimsExchanges>
</OrchestrationStep>
do i need to call TechnicalProfile "REST-AcquireAccessToken" also in user journet step?if yes then when?
Thanks for the update #Munazza Osama , Posting the solution in the answer .
Solution:
The error:Claim "bearerToken" specified for the bearer token is not present in the available claims, got resolved by
Calling the "REST-AcquireAccessToken" Technical Profile to get access token along with calling "REST-API-SignUp" technical profile in User journey.
<OrchestrationStep Order="8" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="RESTGetAccessToken" TechnicalProfileReferenceId="REST-AcquireAccessToken " />
<ClaimsExchange Id="RESTPostUserClaims" TechnicalProfileReferenceId="REST-API-SignUp" />
</ClaimsExchanges>
</OrchestrationStep>

Is msal 2.0 (msal-browser) auth code flow is supported with Azure AD B2C custom policies?

I am trying to use e msal 2.0 (msal-browser) for my react app for authentication with Azure AD B2C Custom policy, I didn't any proper documentation or samples for the same
This sample should be useful to you, it uses Azure AD B2C + Custom Policies + MSAL.js 2.0 + Authorization Code flow.
<!-- The AAD Common Endpoint Claims Provider. Matches on the existence of AAD-Common in the claimsProvider collection -->
<ClaimsProvider>
<DisplayName>Login with AAD OIDC</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AAD-OIDC">
<DisplayName>Login with AAD (OIDC)</DisplayName>
<Description>Login with AAD (OIDC)</Description>
<Protocol Name="OpenIdConnect" />
<OutputTokenFormat>JWT</OutputTokenFormat>
<Metadata>
<Item Key="METADATA">https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration</Item>
<!-- TODO: Create multi-tenant App Registration and add client ID here -->
<Item Key="client_id">xxxxx</Item>
<Item Key="response_types">code</Item>
<Item Key="scope">openid profile</Item>
<Item Key="response_mode">form_post</Item>
<Item Key="HttpBinding">POST</Item>
<Item Key="UsePolicyInRedirectUri">false</Item>
<Item Key="DiscoverMetadataByTokenIssuer">true</Item>
<!-- TODO: Add the Tenant IDs of each Valid Token Issuer -->
<!-- The key below allows you to specify each of the Azure AD tenants that can be used to sign in. Update the GUIDs below for each tenant. -->
<Item Key="ValidTokenIssuerPrefixes">https://login.microsoftonline.com/xxxxx</Item>
<Item Key="ClaimTypeOnWhichToEnable">claimsProvider</Item>
<Item Key="ClaimValueOnWhichToEnable">AAD-Common</Item>
</Metadata>
<CryptographicKeys>
<!-- TODO: Update the storage reference ID for the client secret of the Multi-Tenant App Registration Client -->
<Key Id="client_secret" StorageReferenceId="B2C_1A_ADDMultiTenantAngularSPA" />
</CryptographicKeys>
<InputClaims>
<!--pass the login_hint to Azure AD home realm discovery page to bypass email address entry again-->
<InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="login_hint" />
<!--Disable the prompt on the partner IdP to "Sign in with another account"-->
<InputClaim ClaimTypeReferenceId="hsu" PartnerClaimType="hsu" DefaultValue="1" AlwaysUseDefaultValue="true" />
</InputClaims>
<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" />
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName" />
<OutputClaimsTransformation ReferenceId="CreateUserPrincipalName" />
<OutputClaimsTransformation ReferenceId="CreateAlternativeSecurityId" />
<OutputClaimsTransformation ReferenceId="CreateSubjectClaimFromAlternativeSecurityId" />
</OutputClaimsTransformations>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-SocialLogin" />
<EnabledForUserJourneys>OnItemExistenceInStringCollectionClaim</EnabledForUserJourneys>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
(Moving from Comments to Answer)
MSAL.js 2.0 does not currently support Azure AD B2C for use with the PKCE authorization code flow. At this time, Azure AD B2C recommends using the implicit flow.
Please refer the Note in the document for more information and you can see in the GitHub lib it was stated as Not yet available for B2C.

Custom policy ends with an error 500 on oauth2/authresp

I want to have 2 login providers for my app. Customers would connect with B2C and employees woudl connect with our AAD by SSO. Currently the B2C login for customers works with a SignIn V2 user flow, and our SSO works just fine for any other applications.
I followed these 2 pages to get started, using the exact same names:
https://learn.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-get-started-custom
https://learn.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-setup-aad-custom
They could be clearer but I think I got everything right as far as the XML goes. When I run my custom policy, I get a page with a login form and a button to connect with the AD. If I click the button, I'm redirected to the SSO page and I log in with my user. The first time I'm asked to accept the permissions. So far so good, but after that I get redirected to https://mytenant.b2clogin.com/mytenant.onmicrosoft.com/oauth2/authresp, which gives a generic error 500 page. In the B2C Audit log, I see an event "Federate with an identity provider" with "Status: success" for the same datetime as my login so I believe the login works. Similarly, I can see a successful sign-in in the user's page in the AAD.
Is there something more I need to do that the MSDN pages missed? I should be getting redirected to jwt.ms with a token.
Relevant xml files (redacted):
TrustFrameworkBase.xml (only the parts I've modified):
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TrustFrameworkPolicy
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06"
PolicySchemaVersion="0.3.0.0"
TenantId="mytenant.onmicrosoft.com"
PolicyId="B2C_1A_TrustFrameworkBase"
PublicPolicyUri="http://mytenant.onmicrosoft.com/B2C_1A_TrustFrameworkBase">
<!-- snip default building blocks -->
<ClaimsProviders>
<ClaimsProvider>
<DisplayName>Local Account SignIn</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="login-NonInteractive">
<DisplayName>Local Account SignIn</DisplayName>
<Protocol Name="OpenIdConnect" />
<Metadata>
<Item Key="UserMessageIfClaimsPrincipalDoesNotExist">We can't seem to find your account</Item>
<Item Key="UserMessageIfInvalidPassword">Your password is incorrect</Item>
<Item Key="UserMessageIfOldPasswordUsed">Looks like you used an old password</Item>
<Item Key="ProviderName">https://sts.windows.net/mytenantguid/</Item>
<Item Key="METADATA">https://login.microsoftonline.com/mytenant.onmicrosoft.com/.well-known/openid-configuration</Item>
<Item Key="authorization_endpoint">https://login.microsoftonline.com/mytenant.onmicrosoft.com/oauth2/token</Item>
<Item Key="response_types">id_token</Item>
<Item Key="response_mode">query</Item>
<Item Key="scope">email openid</Item>
<!-- Policy Engine Clients -->
<Item Key="UsePolicyInRedirectUri">false</Item>
<Item Key="HttpBinding">POST</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" PartnerClaimType="username" Required="true" />
<InputClaim ClaimTypeReferenceId="password" Required="true" />
<InputClaim ClaimTypeReferenceId="grant_type" DefaultValue="password" />
<InputClaim ClaimTypeReferenceId="scope" DefaultValue="openid" />
<InputClaim ClaimTypeReferenceId="nca" PartnerClaimType="nca" DefaultValue="1" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" 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="userPrincipalName" PartnerClaimType="upn" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" />
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<!-- snip other default claim providers-->
<!-- snip default user journeys-->
</TrustFrameworkPolicy>
TrustFrameworkExtension.xml
<?xml version="1.0" encoding="utf-8" ?>
<TrustFrameworkPolicy
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06"
PolicySchemaVersion="0.3.0.0"
TenantId="mytenant.onmicrosoft.com"
PolicyId="B2C_1A_TrustFrameworkExtensions"
PublicPolicyUri="http://mytenant.onmicrosoft.com/B2C_1A_TrustFrameworkExtensions">
<BasePolicy>
<TenantId>mytenant.onmicrosoft.com</TenantId>
<PolicyId>B2C_1A_TrustFrameworkBase</PolicyId>
</BasePolicy>
<BuildingBlocks>
</BuildingBlocks>
<ClaimsProviders>
<ClaimsProvider>
<DisplayName>Local Account SignIn</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="login-NonInteractive">
<Metadata>
<Item Key="client_id">ProxyIdentityExperienceFramework_AppId</Item>
<Item Key="IdTokenAudience">IdentityExperienceFramework_AppId</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="client_id" DefaultValue="ProxyIdentityExperienceFramework_AppId" />
<InputClaim ClaimTypeReferenceId="resource_id" PartnerClaimType="resource" DefaultValue="IdentityExperienceFramework_AppId" />
</InputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsProvider>
<Domain>Mycompany</Domain>
<DisplayName>Login using Mycompany</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="MycompanyProfile">
<DisplayName>Mycompany Employee</DisplayName>
<Description>Login with your Mycompany account</Description>
<Protocol Name="OpenIdConnect"/>
<OutputTokenFormat>JWT</OutputTokenFormat>
<Metadata>
<Item Key="METADATA">https://login.windows.net/mytenant.onmicrosoft.com/.well-known/openid-configuration</Item>
<Item Key="ProviderName">https://sts.windows.net/mytenantguid/</Item>
<Item Key="client_id">AzureADB2CApp_AppdId</Item>
<Item Key="IdTokenAudience">AzureADB2CApp_AppdId</Item>
<Item Key="UsePolicyInRedirectUri">false</Item>
<Item Key="response_types">code</Item>
<Item Key="scope">openid</Item>
<Item Key="response_mode">form_post</Item>
<Item Key="HttpBinding">POST</Item>
</Metadata>
<CryptographicKeys>
<Key Id="client_secret" StorageReferenceId="B2C_1A_MycompanySecret"/>
</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" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CreateRandomUPNUserName"/>
<OutputClaimsTransformation ReferenceId="CreateUserPrincipalName"/>
</OutputClaimsTransformations>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
</ClaimsProviders>
<UserJourneys>
<UserJourney Id="SignUpOrSignInMycompany">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signinwithpassword">
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
<ClaimsProviderSelection TargetClaimsExchangeId="MycompanyExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Check if the user has selected to sign in using one of the social providers -->
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="LocalAccountSignUpWithLogonEmail" />
<ClaimsExchange Id="MycompanyExchange" TechnicalProfileReferenceId="MycompanyProfile" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Show self-asserted page only if the directory does not have the user account already (i.e. we do not have an objectId).
This can only happen when authentication happened using a social IDP. If local account was created or authentication done
using ESTS in step 2, then an user account must exist in the directory by this time. -->
<OrchestrationStep Order="3" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SelfAsserted-Social" TechnicalProfileReferenceId="SelfAsserted-Social" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- This step reads any user attributes that we may not have received when authenticating using ESTS so they can be sent
in the token. -->
<OrchestrationStep Order="4" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>authenticationSource</Value>
<Value>socialIdpAuthentication</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="5" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>
</UserJourneys>
</TrustFrameworkPolicy>
SignUpOrSigninMycompany.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<TrustFrameworkPolicy
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://schemas.microsoft.com/online/cpim/schemas/2013/06"
PolicySchemaVersion="0.3.0.0"
TenantId="mytenant.onmicrosoft.com"
PolicyId="B2C_1A_signup_signin_mycompany"
PublicPolicyUri="http://mytenant.onmicrosoft.com/B2C_1A_signup_signin_mycompany">
<BasePolicy>
<TenantId>mytenant.onmicrosoft.com</TenantId>
<PolicyId>B2C_1A_TrustFrameworkExtensions</PolicyId>
</BasePolicy>
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSignInMycompany" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="email" />
<OutputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
<OutputClaim ClaimTypeReferenceId="tenantId" AlwaysUseDefaultValue="true" DefaultValue="{Policy:TenantObjectId}" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
</TrustFrameworkPolicy>
In the Identity Experience Framework panel, I run B2C_1A_signup_signin_mycompany and choose testapp1 with https://jwt.ms as the repyl url.
After reaching out for support on MSDN, which didn't help, I've redone the whole process from scratch and I get past this error though I still end up with an error :
AADB2C90037: An error occurred while processing the request. Please contact administrator of the site you are trying to access.
Which was caused by a missing outputclaim for the objectid.
What solved the problem of this question was 2 misunderstandings on my part from unclear instructions (imo).
The starter pack policies have placeholders you need to replace. Some fields look like placeholders but aren't and I had replaced them.
The claim provider given at step 3 contains transformations and OutputClaim that aren't defined in TrustFrameworkBase.xml. I had simply removed them at first but this time I found their definition on MSDN and added them.

Azure AD B2C Claim resolver: Read user details using objectId from query string

I have to prepopulate user email id in the user journey using the object id passed as query string in authorize URL.
I referred to non protocol parameter claim resolvers
But i am getting exception when i try to read using ObjectId.
TechnicalProfile,
<TechnicalProfile Id="AAD-UserReadUsingObjectIdNew">
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
<Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" DefaultValue="{OAUTH-KV:objId}"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="signInName" />
<!-- Optional claims -->
<OutputClaim ClaimTypeReferenceId="displayName" />
<OutputClaim ClaimTypeReferenceId="otherMails" />
<OutputClaim ClaimTypeReferenceId="givenName" />
<OutputClaim ClaimTypeReferenceId="surname" />
<OutputClaim ClaimTypeReferenceId="country" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="extension_creationsource" />
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
UserJourney,
<UserJourney Id="PasswordChange">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountRead" TechnicalProfileReferenceId="AAD-UserReadUsingObjectIdNew" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountLogin" TechnicalProfileReferenceId="LocalAccountLoginUsingObjectIdAndPassword" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>
URL,
https://tenant.b2clogin.com/tenant.onmicrosoft.com/oauth2/v2.0/authorize?p=B2C_1A_PasswordChange_Mob_HH_NewFlow&client_id=xxxxxx-2415-4bb9-9529-131edxxxxx&nonce=defaultNonce&redirect_uri=https%3A%2F%2Flocalhost%3A44321%2F&scope=openid&response_type=id_token&prompt=login&objId=xxxxxx-5e54-4126-9982-bexxxxxx
AppInsight,
"Statebag": {
"Complex-CLMS": {
"objectId": "{OAUTH-KV:objId}"
}
"Message": "An error occurred while retrieving User using identifier claim type \"objectId\" in tenant \"4722b4c2-6388-4c69-9cfb-f950ea762665\". Error returned was 400/Request_BadRequest: Bad request. Please fix the request before retrying."
Notes:
If i make a Rest API call and sending this ObjectId as inputclaim, It is resolving the value and I am able to get the object id value in API request body properly. But if I use it against to read from AAD, it is not resolving the value
Update:
I was trying to check with login hint works as per Link
But it didn't work for me. Then I used signinorsignup policy from startpack.
It started working for signinorsignup. So I found that,
{OIDC:LoginHint} works in only orchestration step CombinedSignInAndSignUp. It does not work in ClaimsProviderSelection.
I think that is why {OAUTH-KV:objId} is also not working for me as am using ClaimsProviderSelection
Any help will be appreciated.
Please help me to fix this.

Resources