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 Security | Microsoft Entra | Microsoft Entra External ID
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. AmanpreetSingh-MSFT 56,951 Reputation points Moderator
    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' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.