Get email (username) in Claims azure ad b2c signed In with AzureAd like a Social account - azure-ad-b2c

I am using starter pack of custom polices with the SocialAndLocalAccounts package to sign in with an Azure Active Directory account.
I customized the flows with custom attributes and it works well for me.
I need to receive the email used for the login (username = email).
In RelyingParty I have this OutputClaims
<OutputClaim ClaimTypeReferenceId = "signInName" />
<OutputClaim ClaimTypeReferenceId = "signInNames.emailAddress" PartnerClaimType = "email" />
<OutputClaim ClaimTypeReferenceId = "otherMails" />
When a user signs-in with a local b2c account, I get the email
in "signInName" and "email" claims,
but when a user signs-in with an AzureAd account , the claims are empty.
How can I get the email?
How must I write the custom policies (TrustFrameworkBase and TFExtensions) ?
Can you help me ?

When the Azure AD identity is signed-in with for the first time, you must map from the upn claim that is issued by Azure AD to the email claim that is used by Azure AD B2C, so that this email claim can be:
Written as the otherMails property in the user object to the Azure AD B2C directory.
Issued by Azure AD B2C in the ID token to the client application.
To map from the upn claim that is issued by Azure AD to the email claim that is used by Azure AD B2C, add a new <OutputClaim /> to the Azure AD authentication technical profile:
<ClaimsProvider>
<Domain>commonaad</Domain>
<DisplayName>Common AAD</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="Common-AAD">
<DisplayName>Multi-Tenant AAD</DisplayName>
<Protocol Name="OpenIdConnect" />
...
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="upn" />
</OutputClaims>
...
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
The AAD-UserWriteUsingAlternativeSecurityId technical profile converts the email claim to the otherMails claim by invoking the CreateOtherMailsFromEmail claims transformation and then saves the otherMails claim to the user object.
To issue the email claim in the ID token to your client application, add a new <OutputClaim /> to the relying party technical profile:
<RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSignIn" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
...
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="otherMails" PartnerClaimType="emails" />
</OutputClaims>
...
</TechnicalProfile>
</RelyingParty>

Related

Different claims for id and access token

I know how to configure custom claims https://learn.microsoft.com/en-us/azure/active-directory-b2c/configure-tokens?pivots=b2c-custom-policy
The problem is the same claims are included in access token and id token.
I want to include "displayName" claim in the id token, but not in the access token, but I don't see a way to differentiate the two
Its currently not possible to have different claim set in Access Token vs ID Token.
• You can edit the claims in the ID token and the access token in the implicit flow only while the same is not possible for authorization code flow with PKCE since the tokens in auth code flow with PKCE are set on the client side due to which they need to be flushed out first. Also, you can configure the relying party claims to be issued in the ID token and the access token in the custom policies for that application registered in B2C.
• Also, the relying party claims that are configured in the input claims and output claims section in the technical profile of the custom policy form the relying party definition which determines the ID token and the access token respectively. And both the tokens return with the same set of claims. You can configure the claims to be issued in the JWT token in the RP section for the implicit flow as below: -
‘ <RelyingParty>
<DefaultUserJourney ReferenceId="SignUpOrSignIn" />
<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="identityProvider" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
{
...
"sub": "6fbbd70d-262b-4b50-804c-257ae1706ef2",
...
} ‘
Thus, through the token technical profile that you define for each ID and the access token in implicit flow, the claims can be passed and used accordingly.
Please find the below links for more information: -
https://learn.microsoft.com/en-us/azure/active-directory-b2c/session-behavior?pivots=b2c-custom-policy#configure-your-custom-policy

Azure Ad b2c: Get email in Claims after successfully Signin in azure ad b2c

I am using starter pack of custom polices with SocialAndLocalAccounts pack.
It is working fine for me.
But I am facing one issue.I need to get email as claim after successfully login.
I am getting email as claim, once user has been been signed-up and redirects back immediately to application.
but I am not getting it when a user simply signs-in.
How can I get that?
where do I need to write an Output Claim to get the value of email in claim?
Kindly help me.
Thanks
For Chris Padgett's answer, you can add other emails (Alternate email) into the claim.
If you just want to add email claim from the SignIn name into the token, you can just take following steps:
Open your SignUporSignIn.xml file
Replace <OutputClaim ClaimTypeReferenceId="email" /> with <OutputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" />
Save this SignUporSignIn.xml file and upload it to Azure AD B2C to overwrite the policy.
Run the SignUporSignIn policy to test it.
Here is my test result, you can see the email claim in the token:
Hope this helps.
Following describes how you can save, load, and then issue the otherMails claim as emails from the sign-up/sign-in and password reset policies.
When writing a local account: You must create the otherMails claim from the email claim using the CreateOtherMailsFromEmail claims transformation and then persist the otherMails claim in the AAD-UserWriteUsingLogonEmail technical profile:
<TechnicalProfile Id="AAD-UserWriteUsingLogonEmail">
...
<IncludeInSso>false</IncludeInSso>
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="CreateOtherMailsFromEmail" />
</InputClaimsTransformations>
<InputClaims>
...
</InputClaims>
<PersistedClaims>
...
<PersistedClaim ClaimTypeReferenceId="otherMails" />
</PersistedClaims>
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="otherMails" />
</OutputClaims>
...
</TechnicalProfile>
You must then pass the otherMails claim out from the LocalAccountSignUpWithLogonEmail technical profile that is invoked to register a local account:
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
...
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="otherMails" />
</OutputClaims>
</TechnicalProfile>
When writing a social account: The otherMails claim is already created from the email claim and then persisted in the AAD-UserWriteUsingAlternativeSecurityId technical profile.
You must then pass the otherMails claim out from the SelfAsserted-Social technical profile that is invoked to register a social account:
<TechnicalProfile Id="SelfAsserted-Social">
...
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="otherMails" />
</OutputClaims>
</TechnicalProfile>
When reading a local or social account: The otherMails claim is already read in the AAD-UserReadUsingObjectId, AAD-UserReadUsingEmailAddress, and AAD-UserReadUsingAlternativeSecurityId technical profiles.
You must then pass the otherMails claim out from the LocalAccountDiscoveryUsingEmailAddress technical profile that is invoked to recover a local password:
<TechnicalProfile Id="LocalAccountDiscoveryUsingEmailAddress">
...
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="otherMails" />
</OutputClaims>
</TechnicalProfile>
To issue the otherMails claim as emails from the sign-up/sign-in and password reset policies: You must add the otherMails claim as <OutputClaim /> to the relying party policies:
<RelyingParty>
...
<TechnicalProfile Id="PolicyProfile">
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="otherMails" PartnerClaimType="emails" />
</OutputClaims>
</TechnicalProfile>
</RelyingParty>
Another option that is working for me was to extend AAD-UserReadUsingObjectId so that it copies the signInNames.emailAddress claim into email. That brought sign-in into alignment with our other journeys/sub-journeys for integrated sign-up, password reset, and social log-in -- which each populate email during first log-in/sign-up.
All I needed to do was add this to TrustFrameworkExtension.xml (under <ClaimsProviders>):
<ClaimsProvider>
<DisplayName>Azure Active Directory</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AAD-UserReadUsingObjectId">
<OutputClaims>
<OutputClaim
ClaimTypeReferenceId="email"
PartnerClaimType="signInNames.emailAddress"
/>
</OutputClaims>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>

How do I get Azure AD B2C's built-in claims to be returned in the token when I'm using a custom policy?

I've been using the built-in SignUpOrSignIn policy for a while, but I'm now moving to a custom policy.
When I set up the built-in policy, I was able to choose from a list of built-in application claims (like displayName and jobTitle), and select which ones I wanted to be returned in the token when the user signed in.
Now I'm setting up the custom policy I want to do the same thing, but I can't get it to work.
So far, in TrustFrameworkBase I have added a ClaimType of jobTitle:
<ClaimType Id="jobTitle">
<DisplayName>Job Title</DisplayName>
<DataType>string</DataType>
<UserHelpText>Job title.</UserHelpText>
</ClaimType>
I've added the following OutputClaim to the TechnicalProfile with ID login-NonInteractive:
<OutputClaim ClaimTypeReferenceId="jobTitle" PartnerClaimType="jobTitle" />
And I've added the following OutputClaim to the TechnicalProfile with ID SelfAsserted-LocalAccountSignin-Email:
<OutputClaim ClaimTypeReferenceId="jobTitle" />
But the jobTitle claim doesn't come through with the others in the token. I've done the same for given_name and that does work. If I change the first OutputClaim to:
<OutputClaim ClaimTypeReferenceId="jobTitle" PartnerClaimType="given_name" />
then a jobTitle claim does come through, but with the value of the given_name claim. This implies I'm just using the wrong PartnerClaimType but there doesn't seem to be a list of them anywhere.
How can I get the built-in job title attribute to be returned as a claim in the token when the user signs in using their local B2C account?
If you only want to read the jobTitle claim (or other claims) for the user and then issue it (or them) in the token, then you must:
1) Declare the jobTitle claim:
<ClaimType Id="jobTitle">
<DisplayName>Job Title</DisplayName>
<DataType>string</DataType>
<DefaultPartnerClaimTypes>
<Protocol Name="OAuth2" PartnerClaimType="job_title" />
<Protocol Name="OpenIdConnect" PartnerClaimType="job_title" />
</DefaultPartnerClaimTypes>
</ClaimType>
2) Add the jobTitle claim as an output claim to the AAD-UserReadUsingObjectId technical profile:
<TechnicalProfile Id="AAD-UserReadUsingObjectId">
...
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="jobTitle" />
</OutputClaims>
...
</TechnicalProfile>
3) Add the jobTitle claim as an output claim to the relying party technical profile:
<RelyingParty>
...
<TechnicalProfile Id="PolicyProfile">
...
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="jobTitle" />
</OutputClaims>
...
</TechnicalProfile>
</RelyingParty>

How can I map a property from an Azure AD login to a B2C identity?

Following this example https://learn.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-setup-aad-custom we have managed to federate an Azure AD directory ('AD') with an Azure AD B2C directory ('B2C'), so we can have social and self-asserted sign up to a public application, which our work users can also sign into with their normal work IDs. This works well and solves a complex scenario for us.
In the application which is secured with B2C, we need to show AD users content that is relevant to their work identity (specifically we need to filter products based on their work role), but this information is not available to us, since the process of signing up to the app generates a new B2C identity for the user (effectively a proxy for their AD identity).
What we need to do is to map the user's original AD identity onto the new B2C identity. Other properties of the AD user such as Given Name and Surname are already mapped, and that seems to take place here, in the ClaimsProvider element of our custom policy, via the PartnerClaimType property:
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="socialIdpUserId" 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="contosoAuthentication" />
<OutputClaim ClaimTypeReferenceId="identityProvider" DefaultValue="AzureADContoso" />
</OutputClaims>
Indeed, it even appears that the ID we're looking for might be mapped to a property (oid) - but when we later query the B2C graph for the user, this oid property is not returned.
So - how can we map the user's Object ID from the work AD directory onto a property on the new B2C identity that is created?
CREATED on 28 Nov 17
Currently, the object identifier for the Azure AD user (or any external user) is saved to the "alternativeSecurityId" attribute in the Azure AD B2C directory, but this built-in attribute can't be queried via the Azure AD Graph API.
You can, however, create a custom attribute and map the "oid" claim from the Azure AD identity provider to a custom claim that is associated with this custom attribute.
Creating a custom attribute and using this as a custom claim is described at Azure Active Directory B2C: Creating and using custom attributes in a custom profile edit policy.
For your specific scenario, you should:
1: Add a <ClaimType />, declaring the custom claim, to the base policy:
<ClaimType Id="extension_AzureADUserObjectId">
<DisplayName>Azure AD User Object ID</DisplayName>
<DataType>string</DataType>
</ClaimType>
2: Map the "oid" claim in the "SignInWithContoso" technical profile:
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="extension_AzureADUserObjectId" PartnerClaimType="oid" />
</OutputClaims>
3: Add the application and object identifiers for the extensions app to the "AAD-Common" technical profile which is required to read and write the custom claim to the Azure AD B2C directory:
<TechnicalProfile Id="AAD-Common">
<DisplayName>Azure Active Directory</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ApplicationObjectId">Insert the object identifier for the b2c-extensions-app application here</Item>
<Item Key="ClientId">Insert the application identifier for the b2c-extensions-app application here</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="TokenSigningKeyContainer" />
</CryptographicKeys>
...
</TechnicalProfile>
4: Write the custom claim in the "AAD-UserWriteUsingAlternativeSecurityId" technical profile:
<PersistedClaims>
...
<PersistedClaim ClaimTypeReferenceId="extension_AzureADUserObjectId" />
</PersistedClaims>
5: Read the custom claim in the "AAD-UserReadUsingAlternativeSecurityId" technical profile:
<OutputClaims>
...
<OutputClaim ClaimTypeReferenceId="extension_AzureADUserObjectId" />
</OutputClaims>
6: Issue the custom claim in any relying party policies or query it via the Azure AD Graph API.
UPDATED on 15 Feb 18
Since this announcement on 5 Feb 18, the external issuer (i.e., the Azure AD tenant) and the external user identifier (i.e., the object identifier of the Azure AD user) can be read from the "userIdentities" property of the user object in the Azure AD B2C directory, where the "issuerUserId" property contains the Base64-encoding of the external user identifier:
{
"userIdentities": [
{
"issuer": "contoso.com",
"issuerUserId": "Mjk2NzdlNTAtY2MwZS00MmU5LWJhNWMtZjFmMDdkZTUwMDhm"
}
]
}

Limiting Claims by App in Azure AD B2C

We have 3 different applications requiring different sets of extension claims.
Application A - Claim A1, Claim A2, Claim A3
Application B - Claim B1, Claim B2, Claim B3
We defined the six Claims in TrustFrameworkExtensions, updated the various TechnicalProfiles to take the input from user and as well write it to directory.
To support the needs of the individual applications, we created 2 RP files, one for each Application and defined the User Journey's specific to the Apps.
The 6 claims are showing up for both Apps, and we want to restrict by App the Claims.
Tried to copy everything from TrustFrameworkExtensions into RP file, the RP does not load and throws an error as follows
Unable to upload policy. Reason : Validation failed: 3 validation error(s) found in policy "B2C_1A_1182017SIGNUP_SIGNIN" of tenant "XXXXXXXXX.onmicrosoft.com".
A required Metadata item with key "ApplicationObjectId" was not found in the TechnicalProfile with id "AAD-UserWriteUsingAlternativeSecurityId" in policy "B2C_1A_1182017signup_signin" of tenant "XXXXXXXXX.onmicrosoft.com".
A required Metadata item with key "ApplicationObjectId" was not found in the TechnicalProfile with id "AAD-UserWriteUsingLogonEmail" in policy "B2C_1A_1182017signup_signin" of tenant "XXXXXXXXX.onmicrosoft.com".
A required Metadata item with key "ApplicationObjectId" was not found in the TechnicalProfile with id "AAD-UserWriteProfileUsingObjectId" in policy "B2C_1A_1182017signup_signin" of tenant "XXXXXXXXX.onmicrosoft.com".
Appreciate advise and guidance to support multiple Apps with different claims.
To use extension attributes in your custom policy you need to add some configuration to your file involving the b2c-extensions-app that is automatically created and registered in the Portal for each B2C tenant.
In your case, you seem to be missing the ApplicationObjectID and possibly the ClientId of the b2c-extensions-app in the Metadata key section of your AAD-Common technical profile.
The Next Steps section of the Create Custom Attribute documentation describes how to perform this configuration.
https://learn.microsoft.com/en-us/azure/active-directory-b2c/custom-policy-custom-attributes#modify-your-custom-policy
Open the extensions file of your policy. For example, SocialAndLocalAccounts/TrustFrameworkExtensions.xml.
Find the ClaimsProviders element. Add a new ClaimsProvider to the ClaimsProviders element.
Replace ApplicationObjectId with the Object ID that you previously recorded. Then replace ClientId with the Application ID that you previously recorded in the below snippet.
<ClaimsProvider>
<DisplayName>Azure Active Directory</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AAD-Common">
<Metadata>
<!--Insert b2c-extensions-app application ID here, for example: 11111111-1111-1111-1111-111111111111-->
<Item Key="ClientId"></Item>
<!--Insert b2c-extensions-app application ObjectId here, for example: 22222222-2222-2222-2222-222222222222-->
<Item Key="ApplicationObjectId"></Item>
</Metadata>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
Use <RelyingParty><TechnicalProfile><OutputClaims> to control the claims returned.
<RelyingParty>
<DefaultUserJourney ReferenceId="SignInAppA" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="ClaimA1" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>
and
<RelyingParty>
<DefaultUserJourney ReferenceId="SignInAppB" />
<TechnicalProfile Id="PolicyProfile">
<DisplayName>PolicyProfile</DisplayName>
<Protocol Name="OpenIdConnect" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="ClaimB1" />
</OutputClaims>
<SubjectNamingInfo ClaimType="sub" />
</TechnicalProfile>
</RelyingParty>

Resources