azure AD B2C starter pack, for edit profile custom policy,if the user is signed in, authentication is skipped, how to force the user to authenticate? - azure-ad-b2c

this is the journey
<UserJourney Id="ProfileEdit">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsProviderSelection" ContentDefinitionReferenceId="api.idpselections">
<ClaimsProviderSelections>
<ClaimsProviderSelection TargetClaimsExchangeId="LocalAccountSigninEmailExchange" />
</ClaimsProviderSelections>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="4" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="B2CUserProfileUpdateExchange" TechnicalProfileReferenceId="SelfAsserted-ProfileUpdate" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="5" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>
this is the link
https://github.com/Azure-Samples/active-directory-b2c-custom-policy-starterpack/blob/main/LocalAccounts/TrustFrameworkBase.xml

In the starter pack, the single sign-on behaviour is not configured.
By default it uses "Tenant" scope: https://learn.microsoft.com/en-us/azure/active-directory-b2c/session-behavior?pivots=b2c-custom-policy#configure-azure-ad-b2c-session-behavior.
This means the single sign-on session is active in the ProfileEdit policy.
You can configure it to be Policy scoped in ProfileEdit policy:
<!-- inside RelyingParty element, under DefaultUserJourney -->
<UserJourneyBehaviors>
<SingleSignOn Scope="Policy" />
</UserJourneyBehaviors>
You could also set it to Suppressed to disable single sign-on in the ProfileEdit policy.

Related

Replace Azure B2C verification code by link in email during password reset

I have a password reset flow. I'm sending custom email templates using sendgrid. Now I want to change the verification code with a "verification link".
I found a sample for signup invitation that is similar but not really a sample for password reset.
Does somebody already tried this?
Thanks
If you understood the flow in the signup invitation, you could use the same logic to implement a password reset flow.
Instead of sending a link to the signup invitation flow, send an email with a link to your custom password reset flow.
In the user journey, After extracting the email from Id token hint, use a technical profile to read user details.
You can always add an extra layer of security by asking the user to do a multi-factor authentication using phone or email.
After that it's the same steps from the password reset policy to display the password collection page and save the updated password.
The user journey would roughly look something like this
<UserJourney Id="PasswordReset">
<OrchestrationSteps>
<!-- Track that we have received an authentication request -->
<OrchestrationStep Order="1" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="TrackAuthenticationRequest" TechnicalProfileReferenceId="AzureInsights-AuthenticationRequest" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="GetClaims" CpimIssuerTechnicalProfileReferenceId="IdTokenHint_ExtractClaims" />
<OrchestrationStep Order="3" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>email</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="SelfAsserted-Unsolicited" TechnicalProfileReferenceId="SelfAsserted-Unsolicited"/>
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="4" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="UserReadUsingEmailAddressExchange" TechnicalProfileReferenceId="AAD-UserReadUsingEmailAddress" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Track that the authentication step is completed -->
<OrchestrationStep Order="5" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="TrackAuthenticationComplete" TechnicalProfileReferenceId="AzureInsights-AuthenticationComplete" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Optional MFA steps 6 to 8. Replace with email mfa if needed -->
<!-- Track that the mutifactor authentication step is initiated -->
<OrchestrationStep Order="6" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="TrackMultifactorInitiate" TechnicalProfileReferenceId="AzureInsights-MultifactorInitiate" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="7" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="PhoneFactor-Verify" TechnicalProfileReferenceId="PhoneFactor-InputOrVerify" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Track that the mutifactor authentication step is completed -->
<OrchestrationStep Order="8" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="TrackMultifactorComplete" TechnicalProfileReferenceId="AzureInsights-MultifactorComplete" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Track that the password reset flow is started-->
<OrchestrationStep Order="9" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="TrackPasswordResetInitiate" TechnicalProfileReferenceId="AzureInsights-PasswordResetInitiate" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="10" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="NewCredentials" TechnicalProfileReferenceId="LocalAccountWritePasswordUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<!-- Track that the password reset flow is completed-->
<OrchestrationStep Order="11" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="TrackPasswordResetComplete" TechnicalProfileReferenceId="AzureInsights-PasswordResetComplete" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="12" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="13" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
<!-- Track that we have successfully sent a token -->
<OrchestrationStep Order="14" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="TrackTokenIssued" TechnicalProfileReferenceId="AzureInsights-TokenIssued" />
</ClaimsExchanges>
</OrchestrationStep>
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>
In the BuildUrl Method from HomeController in API, change the policy id from app settings with your custom password reset policy id
private string BuildUrl(string token)
{
string nonce = Guid.NewGuid().ToString("n");
return string.Format(this.AppSettings.B2CSignUpUrl,
this.AppSettings.B2CTenant,
this.AppSettings.B2CPasswordResetPolicy,
this.AppSettings.B2CClientId,
Uri.EscapeDataString(this.AppSettings.B2CRedirectUri),
nonce) + "&id_token_hint=" + token;
}
Note: The BuildUrl method may have to be modified once you are using custom domains in production

Difference between CombinedSignInAndSignUp with api.signuporsignin vs ClaimsProviderSelection with api.idpselections

I'm wondering if there is any difference between following sets of orchestration steps:
CombinedSignInAndSignUp with api.signuporsignin
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection TargetClaimsExchangeId="GoogleExchange" />
<ClaimsProviderSelection TargetClaimsExchangeId="FacebookExchange" />
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSigninOnly-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="true">
<Value>objectId</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="GoogleExchange" TechnicalProfileReferenceId="Google-OAuth2" />
<ClaimsExchange Id="FacebookExchange" TechnicalProfileReferenceId="Facebook-OAuth2" />
</ClaimsExchanges>
</OrchestrationStep>
api.signuporsignin is urn:com:microsoft:aad:b2c:elements:contract:unifiedssp:2.1.5
SelfAsserted-LocalAccountSigninOnly-Email is configured with:
<Item Key="setting.showSignupLink">False</Item>
<Item Key="setting.forgotPasswordLinkLocation">none</Item>
so the intention is to sign in only.
This renders a sign in page where user can sign in directly with local account or select external idp provider to sign in with.
ClaimsProviderSelection with api.idpselection
<OrchestrationStep Order="1" Type="ClaimsProviderSelection" ContentDefinitionReferenceId="api.idpselections">
<ClaimsProviderSelections>
<ClaimsProviderSelection TargetClaimsExchangeId="GoogleExchange" />
<ClaimsProviderSelection TargetClaimsExchangeId="FacebookExchange" />
<ClaimsProviderSelection TargetClaimsExchangeId="LocalAccountSigninEmailExchange" />
</ClaimsProviderSelections>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSigninOnly-Email" />
<ClaimsExchange Id="GoogleExchange" TechnicalProfileReferenceId="Google-OAuth2" />
<ClaimsExchange Id="FacebookExchange" TechnicalProfileReferenceId="Facebook-OAuth2" />
</ClaimsExchanges>
</OrchestrationStep>
api.idpselection is urn:com:microsoft:aad:b2c:elements:contract:providerselection:1.2.1
This firstly render a page where user can select Local account, Google or Facebook. Then if user has selected Local account, Self asserted page to sign in is shown, and when he selected Google/Facebook, he is redirected to external idp.
Is there any difference between these two sets of orchestration steps besides slightly different user experience? From my tests it looks like in the end the result is the same - user is authenticated either via local account or external provider and I have access to the same claims in the next steps of my UserJourney.
I have already branded CombinedSignInAndSignUp with api.signuporsignin so now I'm wondering if it's safe to use this combination in different UserJourneys (ProfileUpdate, PasswordChange etc.). Samples often show ClaimsProviderSelection with api.idpselections for such UserJourneys but I do not see any difference and I wouldn't have to brand and change user experience for these UserJourneys.

How to set login button of custom IdP on azure b2c

I want to add my custom IDP integration to my B2C login and I am having trouble in the first step, to put a custom login button on the login page.
I did the same thing with google with success but could not did this with my custom IDP. The only button that appears is google. Any idea on how to add the login button of my custom IDP?
Here's my policy:
<UserJourney Id="SignUpOrSignIn">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection TargetClaimsExchangeId="GoogleExchange" />
<ClaimsProviderSelection TargetClaimsExchangeId="MyCustomExchange" />
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
</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="GoogleExchange" TechnicalProfileReferenceId="Google-OAuth2" />
<ClaimsExchange Id="MyCustomExchange" TechnicalProfileReferenceId="Google-OAuth2" />
</ClaimsExchanges>
</OrchestrationStep>
...
</UserJourney>
I found the answer. Had to set DisplayName on the Technical Profile
<TechnicalProfiles>
<TechnicalProfile Id="MyCustom-OAuth2">
<DisplayName>MyCustom Button</DisplayName>
...
</TechnicalProfiles>
Here's the journey:
<UserJourney Id="SignUpOrSignIn">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signuporsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection TargetClaimsExchangeId="GoogleExchange" />
<ClaimsProviderSelection TargetClaimsExchangeId="MyCustomExchange" />
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
</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="GoogleExchange" TechnicalProfileReferenceId="Google-OAuth2" />
<ClaimsExchange Id="MyCustomExchange" TechnicalProfileReferenceId="MyCustom-OAuth2" />
</ClaimsExchanges>
</OrchestrationStep>
...

Combined Azure B2C Policy Edit and Password Change

I was asked if you can have a single B2C policy that does both Profile Edit and Password Change (not SSPR).
My first thought was 'No - do two cards for that' but now that I'm thinking about it - perhaps something in the user journey could handle this
Before I go down this road, if anyone else tried and succeeded (or failed) that would save some cycles. I try to avoid 'recreating the wheel' or 'hitting dead-ends' unnecessarily..
I tried to implement the scenario and I able to do it. Below are the User Journey Code, before that you need to add one claimtype and one technical profile as below.
Claim type indicates whether user changing the password
<ClaimType Id="isPasswordChangeFlow">
<DisplayName>Indicates whether user changing the password</DisplayName>
<DataType>boolean</DataType>
<AdminHelpText>Add help text here</AdminHelpText>
</ClaimType>
Technical Profile setting the value of the isPasswordChangeFlow output claim to true
<TechnicalProfile Id="StartPasswordChangeFlow">
<DisplayName>Change Your Password</DisplayName>
<Protocol Name="Proprietary" Handler="Web.TPEngine.Providers.ClaimsTransformationProtocolProvider, Web.TPEngine, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
<OutputClaims>
<OutputClaim ClaimTypeReferenceId="isPasswordChangeFlow" DefaultValue="true" />
</OutputClaims>
<UseTechnicalProfileForSessionManagement ReferenceId="SM-Noop" />
</TechnicalProfile>
User Journey
<UserJourney Id="PasswordChangeOrProfileEdit">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsExchange" >
<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="ClaimsProviderSelection" ContentDefinitionReferenceId="api.idpselections">
<ClaimsProviderSelections>
<ClaimsProviderSelection TargetClaimsExchangeId="ProfileEdit" />
<ClaimsProviderSelection TargetClaimsExchangeId="StartPasswordChangeFlowExchange" />
</ClaimsProviderSelections>
</OrchestrationStep>
<OrchestrationStep Order="4" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="ProfileEdit" TechnicalProfileReferenceId="SelfAsserted-ProfileUpdate" />
<ClaimsExchange Id="StartPasswordChangeFlowExchange" TechnicalProfileReferenceId="StartPasswordChangeFlow" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="5" Type="ClaimsExchange">
<Preconditions>
<Precondition Type="ClaimsExist" ExecuteActionsIf="false">
<Value>isPasswordChangeFlow</Value>
<Action>SkipThisOrchestrationStep</Action>
</Precondition>
</Preconditions>
<ClaimsExchanges>
<ClaimsExchange Id="PasswordChangeExchange" TechnicalProfileReferenceId="LocalAccountWritePasswordUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="6" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId1" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="7" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
<ClientDefinition ReferenceId="DefaultWeb" />
</UserJourney>
Make Sure to remove prompt=login parameter from the generated URL to maintain the session.
Reference Link
Output

How can I get a forgot password link on a custom Sign In policy for local accounts?

Using AAD B2C identity experience framework, I am trying to create a custom policy that allows sign-in to a local AADB2C account and includes a "Can’t access your account?" link invoking the built-in self-service functionality. So basically I want the user experience/functionality of the built-in "B2C_1_SignIn_Local" policy, but as part of my suite of custom policies. I do NOT want this userjourney/experience to allow the user to choose a different IdP.
I have been able to create a userjourney that invokes a local sign-in, but the UI doesn't include the "Can’t access your account?" link. The userjourney I have so far looks like this:
<UserJourney Id="SignInB2CLocal">
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsProviderSelection" ContentDefinitionReferenceId="api.idpselections">
<ClaimsProviderSelections>
<ClaimsProviderSelection TargetClaimsExchangeId="SignInWithLogonNameExchange" />
</ClaimsProviderSelections>
</OrchestrationStep>
<OrchestrationStep Order="2" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="SignInWithLogonNameExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" 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="4" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
</UserJourney>
The above is based on a combination of what I found in the built-in policy B2C_1_SignIn_Local (downloaded file) and what I used for other IdPs like AAD. I also tried directly calling the built-in B2C_1_SignIn_Local from my MVC ASP.NET application but got token validation errors.
Is my intended result possible?
thanks!
Martin
You can either:
(i) Change from the ClaimsProviderSelection and ClaimsExchange orchestration steps to the CombinedSignInAndSignUp one with the api.signuporsignin content definition, or
(ii) Change from the api.selfasserted content definition to the api.signuporsignin one for the SelfAsserted-LocalAccountSignin-Email technical profile.
What is important is the <DataUri /> value for the content definition is set to:
urn:com:microsoft:aad:b2c:elements:unifiedssp:1.0.0
which renders the "Forgot your password" and "Sign up now" links.
i) The CombinedSignInAndSignUp orchestration step
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signupsignin">
<ClaimsProviderSelections>
<ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
</ClaimsProviderSelections>
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<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" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="4" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
ii) The LocalAccountSigninEmailExchange technical profile
<TechnicalProfiles>
<TechnicalProfile Id="SelfAsserted-LocalAccountSignin-Email">
<Metadata>
<Item Key="ContentDefinitionReferenceId">api.signuporsignin</Item>
</Metadata>
</TechnicalProfile>
</TechnicalProfiles>
<OrchestrationSteps>
<OrchestrationStep Order="1" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
</ClaimsExchanges>
</OrchestrationStep>
<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" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="3" Type="ClaimsExchange">
<ClaimsExchanges>
<ClaimsExchange Id="AADUserReadWithObjectId" TechnicalProfileReferenceId="AAD-UserReadUsingObjectId" />
</ClaimsExchanges>
</OrchestrationStep>
<OrchestrationStep Order="4" Type="SendClaims" CpimIssuerTechnicalProfileReferenceId="JwtIssuer" />
</OrchestrationSteps>
This is untested but I am pretty sure you change:
ContentDefinitionReferenceId="api.idpselections"
To:
ContentDefinition Id="api.localaccountsignin"
This should just show the local account sign in page with no registration and the password reset.

Resources