B2C Sign-up screen shows {OIDC:LoginHint} instead of the login - azure-ad-b2c

I am passing an email of a prospective member in the login_hint from my website to B2C. In my custom policy I am setting the email claim of the "SignUp" TechnicalProfile to {OIDC:LoginHint}
<TechnicalProfile Id="CustomLocalAccountSignUpWithLogonEmail">
<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>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" DefaultValue="{OIDC:LoginHint}" />
</InputClaims>
<OutputClaims>
But instead of seeing the user's email, the string {OIDC:LoginHint} is displayed in the form:
There is a similar question from 2018 with a suggested workaround of using JavaScript to populate the email field on the Sign Up form. But, I don't use custom templates, so the JavaScript workaround won't work for me.
All I need is to populate the email claim with the value passed in {OIDC:LoginHint}. Is there any way to solve this in the policy XML?
Thank you

In a selfAsserted technical profile, you must:
The IncludeClaimResolvingInClaimsHandling metadata must be set to true.
The input or output claims attribute AlwaysUseDefaultValue must be set to true.
https://learn.microsoft.com/en-us/azure/active-directory-b2c/claim-resolver-overview#using-claim-resolvers
An example of using both settings is here
https://learn.microsoft.com/en-us/azure/active-directory-b2c/claim-resolver-overview#restful-technical-profile

Related

Getting access token for an api protected by B2C, using custom policies

I have an api that is protected using ADB2C authentication. I need to call this api via custom policies. I followed the documentation enter link description here and have added the two technical profiles as validation technical profile of a self asserted profile.
I am getting an access token returned by the below technical profile :
<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://login.microsoftonline.com/{tenant id here}/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="{app id uri for protected resource}/.default" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="bearerToken" PartnerClaimType="access_token" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
And then making the rest api call using below profile :
<TechnicalProfile Id="UserMigrationViaLegacyIdp">
<DisplayName>REST API call to communicate with Legacy IdP</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://99a0a14a6402.ngrok.io/api/Identity/SignUpAsync
</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="SendClaimsIn">Header</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
<Item Key="UseClaimAsBearerToken">bearerToken</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="bearerToken"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="phonePresent"/>
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
However, scopes are missing from the returned access token, hence token validation is failing on the api.
Is my call to get access token missing anything?
For the client credentials grant flow, the API permissions must be created as roles (see How to: Add app roles to your application and receive them in the token) and then granted admin consent (see Admin consent button).
As result, the bearer token contains the roles claim, rather than the scp claim.
The API application checks access using this roles claim (see Verify app roles in APIs called by daemon apps).

Can I recognize/know what the OrchestrationStep I'm?

For example...
I've tried this in InputClaims
<InputClaim ClaimTypeReferenceId="Step" AlwaysUseDefaultValue="true" DefaultValue="SelfAsserted-Social-Step01" />
And that in OutputClaims
<OutputClaim ClaimTypeReferenceId="Step" />
So capture all in Javascript (Client-side) in page in this way:
var stepPage = $("#Step").text();
switch (stepPage) {
case "OS-SignIn":
do_this();
}
Worked for me purpose, but it looks a workaround...
Finally, my question is: How I achieve this behaviour in a sophisticated way, like a var in javascript created by B2C or something like that? More native...
For this use case, you can use a different content definition id for each technical profile.
And then define a matching content definition with matching id, with the respective HTML dataURI for that specific technical profile.
This way you don't need to determine on the front end what orchestrations step is being rendered, as you'll have a HTML specific for each orchestration step.
See below how i create api.page1 as a content definition for this technical profile. Repeat that pattern for each technical profile. Then each page will reference a unique HTML file.
<ContentDefinition Id="api.page1">
<LoadUri>https://your-storage-account.blob.core.windows.net/your-container/customize-ui-page1.html</LoadUri>
<RecoveryUri>~/common/default_page_error.html</RecoveryUri>
<DataUri>urn:com:microsoft:aad:b2c:elements:unifiedssp:1.0.0</DataUri>
<Metadata>
<Item Key="DisplayName">Signin and Signup</Item>
</Metadata>
</ContentDefinition>
<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="SignUpTarget">SignUpWithLogonEmailExchange</Item>
<Item Key="setting.operatingMode">Email</Item>
<Item Key="ContentDefinitionReferenceId">api.page1</Item>

Azure AD B2C - call rest api with parameter in header

I'm trying to call a rest api in a technical profile which requires parameters to be passed to it through the header, but I'm unable to do so. I have:
<TechnicalProfile Id="techProfile1">
<DisplayName>Technical Profile 1</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://xxxxxxx.azurewebsites.net/api/controller/action</Item>
<Item Key="AuthenticationType">Basic</Item>
<Item Key="SendClaimsIn">Header</Item>
<Item Key="AllowInsecureAuthInProduction">true</Item>
</Metadata>
<CryptographicKeys>
<Key Id="BasicAuthenticationUsername" StorageReferenceId="xxxxxx" />
<Key Id="BasicAuthenticationPassword" StorageReferenceId="xxxxxx" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="claimName1" PartnerClaimType="paramName1" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="output1"/>
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
Where the value I'm trying to pass in is the ClaimName1 claim, and the parameter name is paramName1. Am I correct in using the InputClaim section for this?
The response back that I get is: AADB2C90075: The claims exchange 'techProfile1' specified in step '3' returned HTTP error response with Code 'InternalServerError' and Reason 'Internal Server Error'.
Am I right in assuming that the parameter is not being passed to the api? When I change the ServiceUrl to: https://xxxxxxx.azurewebsites.net/api/controller/action?paramName1=yyyy (where yyyy is the value held in the claimName1 claim), then it works as expected.
<Item Key="SendClaimsIn">Header</Item>
instead of the above one try the below one
<Item Key="SendClaimsIn">QueryString</Item>
This will add the input claim as query param.

How to set SendClaimsIn for azure ad b2c REST call

I have created an AAD B2C custom policy which makes a call to call our REST API when a new user signs up by creating a custom Azure AD B2C custom policy.But i have to set two values to REST API. Ocp-Apim-Subscription-Key in header and email id in body.but i have to set SendClaimsIn only as either header or body.
so i added SendClaimsIn as header.But i cdont know how to set both values as inputclaim.My code is
<ClaimsProvider>
<DisplayName>Signup 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://myapicall.io/api/</Item>
<Item Key="SendClaimsIn">Header</Item>
<Item Key="AuthenticationType">Bearer</Item>
<Item Key="AllowInsecureAuthInProduction">false</Item>
</Metadata>
<CryptographicKeys>
<Key Id="BearerAuthenticationToken" StorageReferenceId="B2C_1A_RestApiBearerToken" />
</CryptographicKeys>
<InputClaims>
<!-- Claims sent to your REST API -->
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="grant_type" "DefaultValue"="Ocp-Apim-Subscription-Key"/>
</InputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
</TechnicalProfiles>
</ClaimsProvider>
its shows validation error while uploading
makes a reference to ClaimType with id "Ocp-Apim-Subscription-Key" but
neither the policy nor any of its base policies contain such an
element
i want to set header as Ocp-Apim-Subscription-Key as "12345"
Add the following inside of the <ClaimsSchema> tag near the top of the file:
<ClaimType Id="Ocp-Apim-Subscription-Key">
<DisplayName>OCP APIM Subscription Key</DisplayName>
<DataType>string</DataType>
</ClaimType>
Change the values inside of the <InputClaims> in your REST-ValidateProfile technical profile to the following:
<InputClaims>
<!-- Claims sent to your REST API -->
<InputClaim ClaimTypeReferenceId="email" />
<InputClaim ClaimTypeReferenceId="Ocp-Apim-Subscription-Key" DefaultValue="12345" />
</InputClaims>
You don't need a grant_type input claim for a static OAuth2 bearer (see here).

Howto Enable Email Verification in Azure AD B2C

How do I enable email verification in B2C w/ custom policies?
In an attempt to reverse engineer it, I tried disabling it in a built-in policy and downloaded the policy. I tried adding that metadata item to my self-asserted technical profile but that didn't work.
Reverse Engineer Test | Built-In Policy
<TechnicalProfile Id="SelfAsserted-Input">
<Metadata>
<Item Key="EnforceEmailVerification">False</Item>
</Metadata>
</TechnicalProfile>
My Self-Asserted Technical Profile
<TechnicalProfile Id="LocalAccountSignUp">
<DisplayName>User signup</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="EnforceEmailVerification">True</Item>
</Metadata>
...
</TechnicalProfile>
I'm using usernames for local accounts incase that matters.
Whether a local account is created with an email address- or user name-based sign-in name, you add email verification by adding PartnerClaimType="Verified.Email" to the "email" output claim of your self-asserted technical profile, as follows:
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />

Resources