Azure B2C custom policy - Is there a way to display a claim in a ClaimsProviderSelection orchestration step - azure

I am currently working with Azure B2C custom policies for my Auth flow.
I have a ClaimsProviderSelection orchestration step which shows the user two options:
Send code to their MFA email saved in authentication methods
Lost Email
What I would like to do is show the users email address through the use of a ClaimProvider in either the display text, or the button itself (see below)
If this is not possible, then I would love to be able to add a 'lost email' button on the verification control page itself - like so:
From what I have seen though, it seems this is only available with 'ForgotPasswordExchange' (as seen here: https://learn.microsoft.com/en-us/azure/active-directory-b2c/add-password-reset-policy?pivots=b2c-custom-policy) for passwords and not authentication methods.
If anyone has any experience with customizing ClaimsProviderSelection steps, or adding custom links on orchestration steps your help would be greatly appreciated!
See below for code examples:
Orchestration step:
<OrchestrationStep Order="2" Type="ClaimsProviderSelection" ContentDefinitionReferenceId='api.MFAselections' >
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="false">
<Value>strongAuthenticationEmailAddress</Value>
<Value>strongAuthenticationPhoneNumber</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsProviderSelections>
<ClaimsProviderSelection TargetClaimsExchangeId="MFAVerifyEmailAddress" />
<ClaimsProviderSelection TargetClaimsExchangeId="LostEmailExchange" />
</ClaimsProviderSelections>
</OrchestrationStep>
Technical Profile:
<TechnicalProfile Id="MFA_VerifyEmailAddress">
<DisplayName>SEND TO {Claim:strongAuthenticationEmailAddress}
</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ContentDefinitionReferenceId">MFAVerifyEmail</Item>
<Item Key="IncludeClaimResolvingInClaimsHandling">true</Item>
<!-- <Item Key="setting.showContinueButton">false</Item> -->
<Item Key="setting.showCancelButton">false</Item>
<Item Key="UserMessageIfSessionDoesNotExist">You have exceeded the maximum time allowed.</Item>
<Item Key="UserMessageIfMaxRetryAttempted">You have exceeded the number of retries allowed.</Item>
<Item Key="UserMessageIfInvalidCode">You have entered the wrong code.</Item>
<Item Key="UserMessageIfSessionConflict">Cannot verify the code, please try again later.</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="MFAcomplete" DefaultValue="true" AlwaysUseDefaultValue='true'/>
</InputClaims>
<DisplayClaims>
<DisplayClaim DisplayControlReferenceId="emailVerificationControl" />
</DisplayClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="MFAcomplete" DefaultValue="email" AlwaysUseDefaultValue='true' />
<OutputClaim ClaimTypeReferenceId="isLostEmail" DefaultValue="false" AlwaysUseDefaultValue='true' />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
</TechnicalProfile>

For anyone who is coming across this - this is what I ended up doing:
Add ContentDefinitionParameters with claim to UserJourneyBehaviors in your RelyingParty
<ContentDefinitionParameters> <Parameter Name="email">{Claim:maskedEmail}</Parameter> </ContentDefinitionParameters>
Use JS to grab email claim from source code, and insert to HTML
const parser = new URL(SETTINGS.remoteResource); let email = parser.searchParams.get('email');

Have you tried to do Output Claims transformation on the email, create a claim of type string, then append the email to it, in a previous step. And display that on the screen.

Related

Technical Profile fails to match user account with email (signInNames.emailAddress) claim

Can anyone explain to me (before Azure B2C Custom Policies make me pull what's left of my hair out), why this technical profile fails to ever return an "objectId" when a user account exists in Azure B2C. I am collecting the email claim in a previous screen and calling the technical profile from the orchestration step.
I can see the profile executing in my Application Insights logs and I have confirmed that the email address I use in the claim is in the directory. But every time, no matter which email address I use, I never get an objectId back which means I can never detect if the user exists or not!
Technical Profile
<TechnicalProfile Id="UE-AAD-CheckAccountExistsByEmail">
<Protocol Name="Proprietary"
Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>
<Item Key="UserMessageIfClaimsPrincipalDoesNotExist">An account could not be found for the provided email address.</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId"/>
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
Orchestration Step
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<!-- Skip this if we already have an object id from single signon -->
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectIdFromSession</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<!-- Call a technical profile to see if an account can be found with the email supplied in AD -->
<ClaimsExchange Id="AccountExistsClaim"
TechnicalProfileReferenceId="UE-AAD-CheckAccountExistsByEmail" />
</ClaimsExchanges>
</OrchestrationStep>
You have specified ClaimsTransformationProtocolProvider as the handler.
You need the AAD provider as the handler to make Graph API queries.
Though if AAD-Common already has the Protocol element, you don't need to specify it here again since it'll be included from there.
Like so:
<TechnicalProfile Id="UE-AAD-CheckAccountExistsByEmail">
<!-- You don't actually need this though if AAD-Common has it -->
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.AzureActiveDirectoryProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="Operation">Read</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">false</Item>
<Item Key="UserMessageIfClaimsPrincipalDoesNotExist">An account could not be found for the provided email address.</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="email" PartnerClaimType="signInNames.emailAddress" Required="true"/>
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="objectId"/>
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
ClaimsTransformationProtocolProvider is used for running claims transformations to produce new claims or modify existing claims.
It is not used for querying AAD.

Azure B2 - jit migration failing to authenticate user on password reset - all configured using custom policies

So I have been involved in implementing Azure B2C using custom policies.
I've tried to follow jit v2 migration process from this git repo https://github.com/azure-ad-b2c/user-migration/tree/master/jit-migration-v2
So the legacy system is .net framework 4.6.2 and MS SQL database. I have managed to implement all functionalities needed for B2C with the help of owin libraries.
So B2C is supposed to redirect users back to our website after the forgot password process and it does redirect but the user is not authenticated. Instead, we’re getting this generic error:
"OpenIdConnectMessage.Error was not null, indicating an error. Error: 'server_error'. Error_Description (may be empty): 'AADB2C90037: An error occurred while processing the request. Please contact administrator of the site you are trying to access.
Correlation ID: d38ccb08-4c77-4716-97e0-465f0aebfeb6
Timestamp: 2021-08-09 08:34:22Z
'. Error_Uri (may be empty): 'error_uri is null'."
I need to say that forgot password process with authenticated redirect back works all fine when the user is already migrated to B2C. The problem only happens when the user is a non-migrated user. Both scenarios are using the same custom policies except some ValidationTechnicalProfile are conditional on whether the user has been migrated or not.
Here is piece of our custom policy that is responsible for password reset process:
<!-- PASSWORD RESET first page -->
<TechnicalProfile Id="PasswordResetFirstPage">
<DisplayName>Reset password using email address</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>
<Item Key="IpAddressClaimReferenceId">IpAddress</Item>
<Item Key="ContentDefinitionReferenceId">api.localaccountpasswordreset</Item>
<Item Key="UserMessageIfClaimsTransformationBooleanValueIsNotEqual">Your account has been locked. Contact your support person to unlock it, then try again.</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<IncludeInSso>false</IncludeInSso>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="email" PartnerClaimType="Verified.Email" Required="true" />
<OutputClaim ClaimTypeReferenceId="objectId" />
<OutputClaim ClaimTypeReferenceId="userPrincipalName" />
<OutputClaim ClaimTypeReferenceId="authenticationSource" />
</OutputClaims>
<!-- NOTE: Remove the validation technical profile to the extension policy -->
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmailAddress" ContinueOnError="true" />
<ValidationTechnicalProfile ReferenceId="REST-UserMigration-LocalAccount-PasswordReset1" ContinueOnError="false" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
<!-- PASSWORD RESET second page -->
<TechnicalProfile Id="PasswordResetSecondPage">
<DisplayName>Change password (username)</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ContentDefinitionReferenceId">api.localaccountpasswordreset</Item>
</Metadata>
<CryptographicKeys>
<Key Id="issuer_secret" StorageReferenceId="B2C_1A_TokenSigningKeyContainer" />
</CryptographicKeys>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="newPassword" Required="true" />
<OutputClaim ClaimTypeReferenceId="reenterPassword" Required="true" />
</OutputClaims>
<!-- NOTE: Remove the validation technical profile to the extension policy -->
<ValidationTechnicalProfiles>
<ValidationTechnicalProfile ReferenceId="AAD-UserWritePasswordUsingObjectId">
<!--Don't run this validation technical profile if objectId is not exists (migrated acccount)-->
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="false">
<Value>objectId</Value>
<Action>SkipThisValidationTechnicalProfile</Action>
</Precondition>
</Preconditions>
</ValidationTechnicalProfile>
<ValidationTechnicalProfile ReferenceId="REST-UserMigration-LocalAccount-PasswordReset2">
<!--Don't run this validation technical profile if objectId is exists (existing acccount)-->
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisValidationTechnicalProfile</Action>
</Precondition>
</Preconditions>
</ValidationTechnicalProfile>
<ValidationTechnicalProfile ReferenceId="AAD-MigrateUserUsingLogonEmail">
<!--Don't run this validation technical profile if objectId is exists (existing acccount)-->
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisValidationTechnicalProfile</Action>
</Precondition>
</Preconditions>
</ValidationTechnicalProfile>
<ValidationTechnicalProfile ReferenceId="REST-UserMigration-PasswordUpdate" ContinueOnError="false" />
</ValidationTechnicalProfiles>
</TechnicalProfile>
Generally the whole process works fine: user is migrated to B2C and password is reset but the actual redirect back to our website is just not authenticated. So far the only workaround we have managed to implement is to just redirect user back to login page but it would be nice to understand what's going on and fix it.
I also need to mention that the same migration step works fine for non-migrated users that want to sign in and there is no problem with that scenario.
We have contacted azure support and we already had few calls with them but it looks like they don't know why this happens and they have not been able to help us sort this out.
Any suggestions very appriciated.

AAD B2C SignUpOrSignIn with both verified Email AND verified Phone

Usually we have a signup/signin with either email or phone, but I have a requirement to do signup/signin requiring both verified email and verified phone number as well.
I tried to set this up using default 'User Flows', with MFA for phone/sms enabled, but the number is not accessible via the graph API call for phoneMethods, if it were, I could have also copied the number to the profile (which would mean that it was a verified phone number). Further on the same, enabling Authentication Method, OR even updating (separating phone number with a space char for code and number) the phone number on the profile page causes the phone number to appear via the phoneMethods graph API call, but not before then.
Can someone who's done this before share some insights on their approach or probably share the custom xml policy if possible? I did look into the github sample policies [https://github.com/azure-ad-b2c/samples/tree/master/policies], but I guess there is none with BOTH.
[Edit on the above]
Based on Wes' input, I ended up creating a technical profile as per below and used it into my UserJourney -> Orchestration step, post the PhoneFactor-InputOrVerify step as per below (apologies on the formatting):
<TechnicalProfile Id="AAD-UserWritePhoneNumberUsingObjectId">
<Metadata>
<Item Key="Operation">Write</Item>
<Item Key="RaiseErrorIfClaimsPrincipalAlreadyExists">false</Item>
<Item Key="RaiseErrorIfClaimsPrincipalDoesNotExist">true</Item>
</Metadata>
<IncludeInSso>false</IncludeInSso>
<InputClaims>
<InputClaim ClaimTypeReferenceId="objectId" Required="true" />
</InputClaims>
<PersistedClaims>
<PersistedClaim ClaimTypeReferenceId="objectId" />
<PersistedClaim ClaimTypeReferenceId="Verified.strongAuthenticationPhoneNumber" PartnerClaimType="extension_PhoneNumber" />
</PersistedClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="Verified.strongAuthenticationPhoneNumber" PartnerClaimType="extension_PhoneNumber"/>
</OutputClaims>
<IncludeTechnicalProfile ReferenceId="AAD-Common" />
</TechnicalProfile>
Ofcourse, the "extension_PhoneNumber" was setup in ClaimsSchema as per below:
<ClaimType Id="extension_PhoneNumber">
<DisplayName>Phone Number</DisplayName>
<DataType>string</DataType>
</ClaimType>
Hope this helps someone...
Cheers! ;)
PS: Appreciate any updates to any of the above comments to make it correct/better.
I have done something somewhat similar to this but in my case I verified a new MFA number as my flow resets the users MFA number, but hopefully this will give you an idea. As far as an approach, you could take the standard login flow from the samples -> add verify the email step -> add verify phone number step. I do not know your level of experience with custom policies, but I believe using the sample custom policy for sign in as an initial template will be your best starting place. Then add the two orchestration steps for verification in. Here are slightly modified excerpts from my implementation.
<OrchestrationSteps>
<OrchestrationStep ContentDefinitionReferenceId="api.signin" Order="1" Type="CombinedSignInAndSignUp">
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="EmailVerifyOnSignIn" TechnicalProfileReferenceId="EmailVerifyOnSignIn" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="4" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="NewPhoneFactor" TechnicalProfileReferenceId="PhoneFactor-Verify" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep CpimIssuerTechnicalProfileReferenceId="JwtIssuer" Order="5" Type="SendClaims" />
Steps 1,2 and 5 should be able to be copied directly from the samples with a small change of outputting the email as a read only claim to be used to verify(see below steps).
Your local account signin will need to add a transform that generates the readonly email from sign in name if you choose this route.
So in your local account signin you will have
<OutputClaimsTransformations>
<OutputClaimsTransformation ReferenceId="CopySignInNameToReadOnly" />
</OutputClaimsTransformations>
just after your output claims and the transform that is being used will be as follows:
<ClaimsTransformation Id="CopySignInNameToReadOnly" TransformationMethod="FormatStringClaim">
<InputClaims>
<InputClaim ClaimTypeReferenceId="signInName" TransformationClaimType="inputClaim" />
</InputClaims>
<InputParameters>
<InputParameter Id="stringFormat" DataType="string" Value="{0}" />
</InputParameters>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="readOnlyEmail" TransformationClaimType="outputClaim" />
</OutputClaims>
</ClaimsTransformation>
Be sure to define your readonly claim in the claimstypes section:
<ClaimType Id="readOnlyEmail">
<DisplayName>Email Address</DisplayName>
<DataType>string</DataType>
<UserHelpText />
<UserInputType>Readonly</UserInputType>
</ClaimType>
This is just a simple claim copy transformation.
Steps 3 and 4, which do each of the verification, have the technical profiles similar to below:
<TechnicalProfile Id="EmailVerifyOnSignIn">
<DisplayName>EmailVerifyOnSignIn</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ContentDefinitionReferenceId">api.selfasserted.EmailPage</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="readOnlyEmail" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="readOnlyEmail" PartnerClaimType="Verified.Email" />
</OutputClaims>
</TechnicalProfile>
This will verify the email that was used to sign in, then the following orchestration step will be to verify the MFA.
You will have to make changes to this next technical profile, but the basic idea will be the same as with email, here is a starting point :
<TechnicalProfile Id="PhoneFactor-Verify">
<DisplayName>PhoneFactor</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.PhoneFactorProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="Verified.strongAuthenticationPhoneNumber" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
The end result would be:
User logs in with email and password
User clicks button to verify the email used during login
User verifies phone number
Claims are sent and journey completes

Force user to login after ADB2C signup

When the user signup on the adb2c, I want him to type his login / password, and not being already connected.
I tried to edit the signin_signup policy but without results
In Custom Policies, you can use a self asserted page to show the user that they have successfully signed up, but not allow them to continue the journey from there. This is sometimes referred to as a "block page" in our samples. Since the user cannot continue the journey, a token will not be issued and a session will not be established.
You can instead use a Custom HTML page to allow the user to return to the home page from here.
The user then needs to login again to get an authenticated session.
The block page is shown to be used here:
https://github.com/azure-ad-b2c/samples/blob/4e43fab365e29f002e9e033a4e078bc2091a8494/policies/password-reset-only/policy/TrustFrameworkExtensions.xml#L132
<TechnicalProfile Id="SelfAsserted-BlockSignUpClaimsIssuance">
<DisplayName>BlockSignUpClaimsIssuance Page</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ContentDefinitionReferenceId">api.selfasserted.blockSignUpPage</Item>
<!--Demo: hide the continue and cancel buttons -->
<Item Key="setting.showContinueButton">false</Item>
<Item Key="setting.showCancelButton">false</Item>
</Metadata>
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="GenerateAMessage" />
</InputClaimsTransformations>
<InputClaims>
<InputClaim ClaimTypeReferenceId="userMessage" />
</InputClaims>
<OutputClaims>
<!--Demo: Show the paragraph claim with the message to the user -->
<OutputClaim ClaimTypeReferenceId="userMessage" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
Apply a precondition to this step, such that if the newUser claim exists, that this step is not skipped:
<OrchestrationStep Order="YOUR STEP #" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="false">
<Value>newUser</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SelfAsserted-BlockSignUpClaimsIssuance" />
</ClaimsExchanges>
</OrchestrationStep>

Looking to have Azure B2C custom policy use a custom error page (and pass a value)

UPDATE:
I am able to finally get my custom error page to render. I had to use
<div id="api"></div>
in my view.
My last concern here, which seems impossible, is adding the value of one of my claims (from the idToken passed to my B2C policy when I call it) into the LoadUri of my ContentDefintion.
Here are my TechnicalProfiles:
<TechnicalProfile Id="SelfAsserted-SigningNotReadyError">
<InputClaimsTransformations>
<InputClaimsTransformation ReferenceId="GetUser" />
</InputClaimsTransformations>
<IncludeTechnicalProfile ReferenceId="SelfAsserted-UserError" />
</TechnicalProfile>
<TechnicalProfile Id="SelfAsserted-UserError">
<DisplayName>Unsolicited error message</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.SelfAssertedAttributeProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<Metadata>
<Item Key="ContentDefinitionReferenceId">api.signingerrorlink</Item>
</Metadata>
<InputClaims>
<InputClaim ClaimTypeReferenceId="errorMessage" />
</InputClaims>
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="errorMessage" />
</OutputClaims>
</TechnicalProfile>
and my ContentDefinition
Note: see how I have to hardcode a GUID. :(
signingerror?user=7ec00437-1ad9-4acc-a285-a729003ca99d
<ContentDefinition Id="api.signingerrorlink">
<LoadUri>https://something.azurewebsites.net/signingerror?user=7ec00437-1ad9-4acc-a285-a729003ca99d</LoadUri>
<RecoveryUri>https://something.azurewebsites.net/error</RecoveryUri>
<DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:1.2.0</DataUri>
<Metadata>
<Item Key="DisplayName">Signing Not Ready</Item>
</Metadata>
</ContentDefinition>
ORIGINAL:
I'm in a pickle here. I have been looking through many posts in stackoverflow and over the internet in general. I hope you can help me.
I have a custom B2C policy, which basically accepts a token, performs some functions then returns an access token in the end. That works fine. My issue is that I need to define a step which will trigger a techical profile based on a precondition. The precondition actually works well to.
What I am missing is a way to construct a technicalprofile/contentdefinition to load my own error page (.Net Core 3 controller) in another project but totally accessible (Controllers/SigningErrorController).
My step:
<OrchestrationStep Order="7" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimEquals" ExecuteActionsIf="true">
<Value>isReadyForSigning</Value>
<Value>True</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SelfAsserted-SigningNotReady" TechnicalProfileReferenceId="SelfAsserted-SigningNotReadyError" />
</ClaimsExchanges>
</OrchestrationStep>
Part 2! I need to pass a value to this custom error page. A guid in this case.
If I use the TP for invalidlink then this works. I have tried various custom contentdefinitions similar to:
<ContentDefinition Id="api.signingerrorlink">
<LoadUri>https://something.azurewebsites.net/error</LoadUri>
<RecoveryUri>https://something.azurewebsites.net/signingerror</RecoveryUri>
<DataUri>urn:com:microsoft:aad:b2c:elements:globalexception:1.1.0</DataUri>
<Metadata>
<Item Key="DisplayName">Error page</Item>
</Metadata>
</ContentDefinition>
...with the signingerror being the custom error page I want to go to.
If I run this, the policy just skips over the step completely. If I use the invalid link TP, then it works. I've tried to figure out also how to pass a value to the error page. I'm at a loss folks.
Any help you can give would be much appreciated.
You can use a claim resolver in the LoadUri element. E.g.:
<ContentDefinition Id="api.signingerrorlink">
<LoadUri>https://something.azurewebsites.net/signingerror?user={Claim:packageUserId}</LoadUri>
<RecoveryUri>https://something.azurewebsites.net/error</RecoveryUri>
<DataUri>urn:com:microsoft:aad:b2c:elements:contract:selfasserted:1.2.0</DataUri>
<Metadata>
<Item Key="DisplayName">Signing Not Ready</Item>
</Metadata>
</ContentDefinition>
https://learn.microsoft.com/en-us/azure/active-directory-b2c/claim-resolver-overview#content-definition

Resources