Can we set custom headers on RESTful API calls in Azure Active Directory B2C custom policies? - azure

I have successfully created an AAD B2C custom policy which makes a call to my application.
Similar to what can be found here:
Integrate REST API claims exchanges in your Azure AD B2C user journey as validation on user input
and here:
Secure your RESTful services using client certificates
<ClaimsProvider>
<DisplayName>XYZ API</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="XYZ">
<DisplayName>XYZ</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://example.com/api/1.0/Users</Item>
<Item Key="AuthenticationType">ClientCertificate</Item>
<Item Key="SendClaimsIn">Body</Item>
</Metadata>
<CryptographicKeys>
<Key Id="ClientCertificate" StorageReferenceId="B2C_1A_XYZRestClientCertificate" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="givenName" PartnerClaimType="givenName" />
<InputClaim ClaimTypeReferenceId="surname" PartnerClaimType="surname" />
<InputClaim ClaimTypeReferenceId="displayName" PartnerClaimType="displayName" />
<InputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="objectId" />
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
<InputClaim ClaimTypeReferenceId="otherMails" PartnerClaimType="otherMails" />
</InputClaims>
<OutputClaims>
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
Our app likes to use custom HTTP headers to track some information about the caller, such as a transaction id. Is it possible to add HTTP headers similar to claims? Something maybe like:
<InputHeaders>
<InputHeader ClaimTypeReferenceId="objectId" HeaderName="transactionId" />
<InputHeader Value="AzureB2C" HeaderName="callerName" />
</InputHeaders>

Right now, it is not possible to split some claims between various places (e.g. body, headers, query string). I suggest you add a request for this feature at the Azure feedback portal for Azure Active Directory.

Related

Azure AD B2C access claim/information from incoming login request

Currently, using B2C with custom policies having moved from Auth0. It was possible within Auth0 to access the scope claim/property of an incoming login request from the UI and then use that value within Rules to apply some logic. This doesn't seem to be easily do-able in B2C
My user journey allows a user to login using their Azure / Office 365 login via an AD Connector, then enrich the user's claim by calling one of my APIs to get more information about that user account before returning the updated claims to the UI. This all works fine.
What I want to do is expand the enrichment request to include the Audience value from the incoming login request. I have multiple front-end applications that use B2C and want different extra info included in the claims sent back to the UI so filtering on Client ID of the Azure AD APP used by the UI would be good. I would also like to see/access the Scope from the incoming login request as it has some information I would like send to the backend API.
I've tried the following but it doesn't like aud or audience as a claim name and scope is always null.
<TechnicalProfile Id="REST-API">
<DisplayName>Enrich User</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://xxx.mydomain.com/users/b2c</Item>;
<Item Key="SendClaimsIn">Body</Item>
<!-- Set AuthenticationType to Basic or ClientCertificate in production environments -->
<Item Key="AuthenticationType">ApiKeyHeader</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
</Metadata>
<CryptographicKeys>
<Key Id="Authorization" StorageReferenceId="B2C_1A_RestApiKey" />
</CryptographicKeys>
<InputClaims>
<!-- Claims sent to your REST API -->
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="givenName" />
<InputClaim ClaimTypeReferenceId="surname" />
<InputClaim ClaimTypeReferenceId="aud" />
<InputClaim ClaimTypeReferenceId="scope" />
<InputClaim ClaimTypeReferenceId="scp" />
<InputClaim ClaimTypeReferenceId="objectId" PartnerClaimType="sub"/>
</InputClaims>
<OutputClaims>
<!-- Claims parsed from your REST API -->
<OutputClaim ClaimTypeReferenceId="isEnabled" />
<OutputClaim ClaimTypeReferenceId="userId" />
<OutputClaim ClaimTypeReferenceId="accountCode" />
<OutputClaim ClaimTypeReferenceId="role" />
<OutputClaim ClaimTypeReferenceId="env" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
You can get scope with claims resolvers.
Ensure you set the settings.
A more generic way is this.

Calling secure REST API from Azure B2C custom policy to embed claims

I am trying to consume a Azure B2C secured API as part of the user journey by creating custom policies. I have created a claims provider to procure a bearer token as below
<ClaimsProvider>
<DisplayName>REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="SecureREST-AccessToken">
<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://***.b2clogin.com/***.onmicrosoft.com/B2C_1A_SignUpOrSignIn/oauth2/v2.0/authorize</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://***.onmicrosoft.com/profileapi/profileapi-scope" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="bearerToken" PartnerClaimType="access_token" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
And another claims provider to call my secure REST API as below
<ClaimsProvider>
<DisplayName>REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="AzureFunctions-GetRole">
<DisplayName>Get Roles </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://***.azurewebsites.net/api/UserProfiles/CheckAdminUser</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="SendClaimsIn">Body</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="email" />
<InputClaim ClaimTypeReferenceId="signInNames.emailAddress" PartnerClaimType="email" />
<InputClaim ClaimTypeReferenceId="bearerToken"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="IsAdminUser" PartnerClaimType="IsAdminUser" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
How do I tie these two up? Should these be two steps in the user journey?
AAD B2C endpoint doesn’t support client credentials flow. Your initial call to get a token should model AAD client credentials flow:
https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow
You would call these technical profiles from the user journey if they return no possibility of an error to the user. Or otherwise as validation technical profiles referenced from a self asserted technical profile.

Azure B2C not sending email address as input claim to REST API validation service

I'm trying to retrieve claims from a REST API service as described in https://learn.microsoft.com/en-us/azure/active-directory-b2c/custom-policy-rest-api-claims-exchange. I'm trying to pass in the login email addres as an InputClaim along with another input claim (AzureTenantID). For some reason the API is always receiving the email InputClaim as empty. The other claim is populated, because it has a default value.
My understanding from the documentation is that this should work but for some reason it does not. Can anyone help me understand what I might be doing wrong? Do I have to specify a value for email?
My redacted technical profile is below. Thank you.
<TechnicalProfiles>
<!-- Custom Restful service -->
<TechnicalProfile Id="REST-API-ValidateEmail">
<DisplayName>Validate user's input data and return UserId claim</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://[servicename].azurewebsites.net/[methodname]</Item>
<Item Key="SendClaimsIn">Body</Item>
<!-- Set AuthenticationType to Basic or ClientCertificate in production environments -->
<Item Key="AuthenticationType">Basic</Item>
<!-- REMOVE the following line in production environments -->
<!--<Item Key="AllowInsecureAuthInProduction">true</Item>-->
</Metadata>
<CryptographicKeys>
<!-- B2C_1A_B2cRestClientId = WebServiceUser -->
<Key Id="BasicAuthenticationUsername" StorageReferenceId="B2C_1A_B2cRestClientId" />
<Key Id="BasicAuthenticationPassword" StorageReferenceId="B2C_1A_B2cRestClientSecret" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="AzureTenantId" PartnerClaimType="AzureTenantId" DefaultValue="[tenant].onmicrosoft.com" />
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="UserId" PartnerClaimType="UserId" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
<!-- Change LocalAccountSignUpWithLogonEmail technical profile to support your validation technical profile -->
<TechnicalProfile Id="LocalAccountSignUpWithLogonEmail">
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="UserId" PartnerClaimType="UserId" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="REST-API-ValidateEmail" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
</TechnicalProfiles>
Please refer this GitHub link to Integrate REST API claims exchanges in your Azure AD B2C user journey to validate user input.
Technical profile
<ClaimsProvider>
<DisplayName>REST APIs</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="REST-ValidateProfile">
<DisplayName>Check loyaltyId 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>
<Item Key="ServiceUrl">https://your-account.azurewebsites.net/api/ValidateProfile?code=your-code</Item>
<Item Key="SendClaimsIn">Body</Item>
<!-- Set AuthenticationType to Basic or ClientCertificate in production environments -->
<Item Key="AuthenticationType">None</Item>
<!-- REMOVE the following line in production environments -->
<Item Key="AllowInsecureAuthInProduction">true</Item>
</Metadata>
<InputClaims>
<!-- Claims sent to your REST API -->
<InputClaim ClaimTypeReferenceId="loyaltyId" />
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="userLanguage" PartnerClaimType="lang" DefaultValue="{Culture:LCID}" AlwaysUseDefaultValue="true" />
</InputClaims>
<OutputClaims>
<!-- Claims parsed from your REST API -->
<OutputClaim ClaimTypeReferenceId="promoCode" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
#Jas-Suri provided the correct answer in comments above. The proper claim to use in this scenario is signInName.

Azure B2C disable Sign up of a SignUpAndSignIn policy

I need some advice on Customising Azure B2C.
I've been looking at both portal based customisation and the Identity Experience Framework.
My key requirement is to have full control of the look and feel of the login experience. However, users must not be able sign up as this is handled by a separate business process. I understand that I cannot use a simple SignIn policy as B2C doesn't provide the required level of customisation.
I'm unable to find any solid documentation that describe how/if this is possible.
I've followed this documentation for the Azure B2C Identity Experience Framework. But can't see where I would be able to disable signup.
https://learn.microsoft.com/en-us/azure/active-directory-b2c/active-directory-b2c-get-started-custom
You can disable the sign-up button using the setting.showSignupLink metadata:
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
<DisplayName>Local Account Signin</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="setting.operatingMode">Email</Item>
<Item Key="setting.showSignupLink">false</Item>
<Item Key="ContentDefinitionReferenceId">api.selfasserted</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="signInName" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="login-NonInteractive" />
</ValidationTechnicalProfiles>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>

Can you pass password claims between steps in Azure AD B2C Custom Policies?

Can you pass password claims between steps in Azure AD B2C Custom Policies?
My symptom is that after signing up using a multiple page custom policy, a user cannot sign in until they reset their password.
I am asking this as I spent many hours debugging a problem that it turns out could not be fixed. I found the answer under another question (Azure AD B2C Multi steps custom policy) that was differently worded but had similar symptoms.
I am posting here in the hope it is more easily found and helpful to others. Apologies if you think this is a duplicate.
In short, no. See Azure AD B2C Multi steps custom policy.
A password claim is "scoped" to a given step. This means the orchestration step that collects the password claim from the end user must be the same step that writes it to the User object.
I was looking for the same and have found a way to do multi step sign up. I tried several methods, including a outputclaimstransformation to store the password in another claim, but that did not work out. Because I already needed to do some input validation against an API I found a way to also copy the password to a new claim (plaintextPassword) that is not scoped to one orchestration step. This claim can be used in a later step to create the user account with the password provided by the plaintextPassword claim.
Create a self asserted technical profile that has an inputclaim (the password) and a validation technical profile. In the validation technical profile you can copy the password to a claim of type string with an inputclaimstransformation. Then add the new claim as outputclaim to the validation profile and to the technical profile. See code below for an example:
<ClaimType Id="plaintextPassword">
<DisplayName>password</DisplayName>
<DataType>string</DataType>
<UserInputType>TextBox</UserInputType>
</ClaimType>
<ClaimType Id="password">
<DisplayName>Your password</DisplayName>
<DataType>string</DataType>
<UserHelpText>Your password</UserHelpText>
<UserInputType>Password</UserInputType>
</ClaimType>
<ClaimsTransformation Id="CopyPassword" TransformationMethod="FormatStringClaim">
<InputClaims>
<InputClaim ClaimTypeReferenceId="password" TransformationClaimType="inputClaim" />
</InputClaims>
<InputParameters>
<InputParameter Id="stringFormat" DataType="string" Value="{0}" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="plaintextPassword" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>
<TechnicalProfile Id="SignUp-PasswordValidation">
<DisplayName>Email signup</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.RestfulProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ServiceUrl">url</Item>
<Item Key="AuthenticationType">ClientCertificate</Item>
<Item Key="SendClaimsIn">Body</Item>
</Metadata>
<CryptographicKeys>
<Key Id="ClientCertificate" StorageReferenceId="B2C_1A_ClientCertificate" />
</CryptographicKeys>
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="CopyPassword" />
</InputClaimsTransformations>
<InputClaims>
<InputClaim ClaimTypeReferenceId="claim_to_validate" PartnerClaimType="claim_to_validate" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="plaintextPassword" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
<TechnicalProfile Id="SignUp">
<DisplayName>Email signup</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.localaccountsignup</Item>
<Item Key="setting.retryLimit">3</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" Required="true" />
<OutputClaim ClaimTypeReferenceId="claim_to_validate" Required="true" />
<OutputClaim ClaimTypeReferenceId="password" Required="true" />
<OutputClaim ClaimTypeReferenceId="executed-SelfAsserted-Input" DefaultValue="true" />
<OutputClaim ClaimTypeReferenceId="plaintextPassword" />
</OutputClaims>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="SignUp-Validation" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
In the technical profile where you create the user in AAD add this line:
<PersistedClaim ClaimTypeReferenceId="plaintextPassword" PartnerClaimType="password"/>
I was able to solve the problem. When we have to add the user information (LocalAccountSignUpWithLogonEmail) I removed the validation that called the technical profile that is written in AAD, I changed it to a validation that calls another technical profile. This will copy our password through a ClaimsTransformation that will save our password in another InputClaim to be visible in any other step of our flow.
<ClaimType Id="plaintextPassword">
<DisplayName>password</DisplayName>
<DataType>string</DataType>
</ClaimType>
<ClaimType Id="passwordTransformation">
<DisplayName>requestSocialRestSecondCall</DisplayName>
<DataType>string</DataType>
</ClaimType>
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="TransformationPassword" />
</ValidationTechnicalProfiles>
<ClaimsProvider> <!-- Copy Password-->
<DisplayName>Copy Password</DisplayName>
<TechnicalProfiles>
<TechnicalProfile Id="TransformationPassword">
<DisplayName>Copy Pass</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<InputClaims>
<InputClaim ClaimTypeReferenceId="passwordTransformation" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="passwordTransformation" />
</OutputClaims>
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="Generate_TranformationPassword" />
</OutputClaimsTransformations>
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
<ClaimsTransformation Id="Generate_TranformationPassword" TransformationMethod="CopyClaim">
<InputClaims>
<InputClaim ClaimTypeReferenceId="newPassword" TransformationClaimType="inputClaim" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="plaintextPassword" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>
I removed the validation that called the technical profile that is written in AAD and changed it to a validation that calls another technical profile.
This will copy the password through a ClaimsTransformation that will save our password in another InputClaim to be visible in any other step of our flow.
<TechnicalProfile Id="SignUp-PasswordValidation">
<Metadata>
<Item Key="ServiceUrl">url</Item>
<Item Key="AuthenticationType">ClientCertificate</Item>
<Item Key="SendClaimsIn">Body</Item>
</Metadata>
What is the url you used?
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
What was you application to create the Secret?

Resources