AAD B2C - Prepopulate email during password reset flow

Maximilian Bürgi 116 Reputation points
2022-03-02T09:15:14.467+00:00

I have set up a custom flow with a unified sign-in sign-up page with password reset link. Now I'd like to simplify the user experience by copying the email that was entered on the sign-in page to the password reset page if the password reset link was pressed.
Curiously the email is already forwarded to the password reset subjourney with a query parameter "...&hint=email" but I can't access this with claim resolvers. I tried {OIDC:LoginHint} which obviously didn't work since the paramter is hint and not login_hint but {OAUTH-KV:hint} also did not work even though it should as far as I understand it.

Is there even any use to the "hint" query parameter? Or did I overlook another way to prepopulate the email field?

Relevant code excerpts:

<UserJourneys>
        <UserJourney Id="SignInLevel1">
            <OrchestrationSteps>
                <OrchestrationStep Order="1" Type="CombinedSignInAndSignUp" ContentDefinitionReferenceId="api.signin">
                    <ClaimsProviderSelections>
                        <ClaimsProviderSelection TargetClaimsExchangeId="AppleExchange" />
                        <ClaimsProviderSelection TargetClaimsExchangeId="FacebookExchange" />
                        <ClaimsProviderSelection TargetClaimsExchangeId="GoogleExchange" />
                        <ClaimsProviderSelection TargetClaimsExchangeId="TwitterExchange" />
                        <ClaimsProviderSelection TargetClaimsExchangeId="ForgotPasswordExchange" />
                        <ClaimsProviderSelection ValidationClaimsExchangeId="LocalAccountSigninEmailExchange" />
                    </ClaimsProviderSelections>
                    <ClaimsExchanges>
                        <ClaimsExchange Id="LocalAccountSigninEmailExchange" TechnicalProfileReferenceId="SelfAsserted-LocalAccountSignin-Email" />
                    </ClaimsExchanges>
                </OrchestrationStep>

                <!-- Registration -->

                <OrchestrationStep Order="2" Type="ClaimsExchange">
                    <Preconditions>
                        <Precondition Type="ClaimsExist" ExecuteActionsIf="true">
                            <Value>authenticationSource</Value>
                            <Action>SkipThisOrchestrationStep</Action>
                        </Precondition>
                    </Preconditions>
                    <ClaimsExchanges>
                        <ClaimsExchange Id="SignUpWithLogonEmailExchange" TechnicalProfileReferenceId="SetRegistrationValues" />
                        <ClaimsExchange Id="GoogleExchange" TechnicalProfileReferenceId="Google-OAUTH" />
                        <ClaimsExchange Id="FacebookExchange" TechnicalProfileReferenceId="Facebook-OAUTH" />
                        <ClaimsExchange Id="TwitterExchange" TechnicalProfileReferenceId="Twitter-OAUTH1" />
                        <ClaimsExchange Id="AppleExchange" TechnicalProfileReferenceId="Apple-OIDC" />
                        <ClaimsExchange Id="ForgotPasswordExchange" TechnicalProfileReferenceId="ForgotPassword" />
                    </ClaimsExchanges>
                </OrchestrationStep>

                <!-- Trouble sign in -->
                <OrchestrationStep Order="3" Type="InvokeSubJourney">
                    <Preconditions>
                        <Precondition Type="ClaimsExist" ExecuteActionsIf="false">
                            <Value>isForgotPassword</Value>
                            <Action>SkipThisOrchestrationStep</Action>
                        </Precondition>
                    </Preconditions>
                    <JourneyList>
                        <Candidate SubJourneyReferenceId="TroubleSignInResetPassword" />
                    </JourneyList>
                </OrchestrationStep>
                            [...]
        </UserJourney>
</UserJourneys>

<SubJourneys>
        <SubJourney Id="TroubleSignInResetPassword" Type="Call">
            <OrchestrationSteps>
                <OrchestrationStep Order="1" Type="ClaimsExchange">
                    <ClaimsExchanges>
                        <ClaimsExchange Id="VerifyMailAddress-TroubleSignIn" TechnicalProfileReferenceId="VerifyMailAddress-TroubleSignIn" />
                    </ClaimsExchanges>
                </OrchestrationStep>
                            [...]
            </OrchestrationSteps>
        </SubJourney>
</SubJourneys>


<ClaimsProvider>
            <DisplayName>Local Account Sign in</DisplayName>
            <TechnicalProfiles>
                                <TechnicalProfile Id="ForgotPassword">
                        <DisplayName>Forgot 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="isForgotPassword" DefaultValue="true" AlwaysUseDefaultValue="true"/>
                        </OutputClaims>
                    </TechnicalProfile>

                    <TechnicalProfile Id="VerifyMailAddress-TroubleSignIn">
                        <Metadata>
                            <Item Key="ContentDefinitionReferenceId">api.trouble_email_verification</Item>
                        </Metadata>
                        <InputClaims>
                            <InputClaim ClaimTypeReferenceId="email" />
                        </InputClaims>
                        <OutputClaims>
                            <OutputClaim ClaimTypeReferenceId="objectId" />
                            <OutputClaim ClaimTypeReferenceId="email" />
                            <OutputClaim ClaimTypeReferenceId="displayName" />
                            <OutputClaim ClaimTypeReferenceId="givenName" />
                            <OutputClaim ClaimTypeReferenceId="surname" />
                            <OutputClaim ClaimTypeReferenceId="extension_personalisationname" />
                            <OutputClaim ClaimTypeReferenceId="extension_language" />
                            <OutputClaim ClaimTypeReferenceId="isRegistration"  DefaultValue="false" AlwaysUseDefaultValue="true"/>
                            <OutputClaim ClaimTypeReferenceId="authenticationSource" DefaultValue="localAccountAuthentication" AlwaysUseDefaultValue="true" />
                        </OutputClaims>
                        <ValidationTechnicalProfiles>
                            <ValidationTechnicalProfile ReferenceId="AAD-UserReadUsingEmail" />
                        </ValidationTechnicalProfiles>
                        <IncludeTechnicalProfile ReferenceId="getMailAddress" />
                        <UseTechnicalProfileForSessionManagement ReferenceId="SM-AAD" />
                    </TechnicalProfile>
            </TechnicalProfiles>
</ClaimsProvider>
Microsoft Entra External ID
Microsoft Entra External ID
A modern identity solution for securing access to customer, citizen and partner-facing apps and services. It is the converged platform of Azure AD External Identities B2B and B2C. Replaces Azure Active Directory External Identities.
3,001 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. AmanpreetSingh-MSFT 56,731 Reputation points
    2022-03-03T16:26:10.07+00:00

    Hi @Maximilian Bürgi • Thank you for reaching out.

    I tested this out for my Password Reset custom policy and got it working using {OAUTH-KV:hint} claim resolver and it pre-populated the email address for me.

    179793-image.png

    You can use THIS URL and update the value of the hint parameter at the end of the URL to see it in action.

    Why I think it didn't work for you could be because the sub-journey is not redirecting you to an OAuth (oauth2/v2.0/authorize) endpoint, rather it is redirecting you to a URL like https://my.b2clogin.com/my.onmicrosoft.com/B2C_1_SuSi3/api/CombinedSigninAndSignup/unified?claimsexchange=ForgotPassword..... To run a Password Reset flow instead of the subjourney, you may consider using the Password reset policy (legacy) method.

    -----------------------------------------------------------------------------------------------------------

    Please "Accept the answer" if the information helped you. This will help us and others in the community as well.

    1 person found this answer helpful.

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.