Quote of the Day

more Quotes

Categories

Buy me a coffee

  • Home>
  • security>

Integrate Azure AD B2C reset password user flow in angular using oidc-client-js.

This post continues from previous posts which I go over using oidc-client-js to interact with azure adb2c:

In this post, I’m going to share how to handle resetting password.

You can find the sample project here.

Create the reset password user flow

At the time of writing, Azure ADB2C has a predefined, standard version of the reset password flow. However, Microsoft recommends using a new version of the reset password flow, as Microsoft no longer updates and maintains the standard versions. For more info, checkout the document.

If you forgot how to create a new user flow, checkout the document, or look at my previous post. Once you have created the flow, make note of the URL as that is where you will send the user to reset the password.

Reference the reset password user flow

In the sample app, the codes handle building the full URL based on the known pattern, as the below snippets show.

get resetPasswordRoute() {
    return this.buildRoute({ policyName: this.resetPasswordPolicy });
}
private buildRoute(options: RouteBuilderOptions): string {
    const url = new URL(
      `https://${this.tenantName}.b2clogin.com/${this.tenantName}.onmicrosoft.com/oauth2/v2.0/authorize`
    );
    url.searchParams.append('p', options.policyName);
    url.searchParams.append('client_id', this.client_id);
    url.searchParams.append('nonce', 'defaultNonce');
    url.searchParams.append(
      'redirect_uri',
      options.redirectUri ? options.redirectUri : this.redirect_uri
    );
    url.searchParams.append('scope', options.scope ? options.scope : 'openid');
    url.searchParams.append(
      'response_type',
      options.responseType ? options.responseType : 'id_token'
    );
    if (options.promptLogin) {
      url.searchParams.append('prompt', 'login');
    }
    return url.href;
  }

In the above snippets, value of resetPasswordPolicy comes from the oidc-settings.json file under the assets folder, as shown below.

{
  "client_id": "47ea6724-b21f-46de-9d17-7425920f77e4",
  "signupSigninPolicy": "b2c_1_signupandsignin",
  "tenantName": "taithienbo",
  "response_type": "id_token token",
  "loadUserInfo": false,
  "response_mode": "fragment",
  "scope": "https://taithienbo.onmicrosoft.com/mywebapi/user_impersonation openid profile",
  "editProfilePolicy": "B2C_1_a_profile_edit",
  "resetPasswordPolicy": "B2C_1_Password_Reset_2"
}

Handle Forgot Password

The sign up and sign in user flow has the Forgot Password link which the user can click on to reset the password. Clicking on the link brings the user back to the app via the redirect url which you can specify as part of the settings you pass into the constructor of the UserManager object. For more information, checkout my previous post, or oidc-client-js document.

Azure ADB2C forgot password link in Sign Up / Sign In page

When redirecting the user back to the app, azure includes the hint that the user has forgotten the password in the url fragment, as in the following example url:

http://localhost:4200/#error=access_denied&error_description=AADB2C90118:+The+user+has+forgotten+their+password.%0D%0ACorrelation+ID:+be33615b-3c47-46aa-add6-6cb2e158bace%0D%0ATimestamp:+2020-11-28+18:56:49Z%0D%0A&state=cf99e9fb510740278ef8636618bc830e

Based on the error code and message in the fragment, we can detect and react to the forgot password scenario, as the below snippets demonstrate.

ngOnInit() {
    ....
    const idTokenKeyWord = 'id_token';
    const errorDescriptionKeyWord = 'error_description';
    const resetPasswordCode = 'AADB2C90118';
    const idToken = params.get(idTokenKeyWord);
        this.route.fragment.subscribe((fragment) => {
          const params = new URLSearchParams(fragment);
          const errorDescription = params.get(errorDescriptionKeyWord);
          if (idToken) {
            this.handleIdToken();
          }
          else if (
            errorDescription &&
            errorDescription.includes(resetPasswordCode)
          ) {
            this.handlePasswordReset();
          }
        });
      }
    });
  }

private handlePasswordReset() {
    // we simply redirect the user to the reset password page.
    window.location.href = this.authService.settings.resetPasswordRoute;
  }

On password reset success

Once the user has successfully reset the password and come back to the app, azure adb2c redirects the user back to the app. In the browser url, the id token is present. However, from my experience, we cannot do a silent login although we have the id token. Silent login works for when the user has finished editing the profile. But for resetting the password, the user needs to login again.

  private handleIdToken() {
    // If the user has come back from the edit profile page, the
    // user object is still present in the storage, and we can do a
    // silent login to pick up any changes to the profile if desired. However,
    // if the user has reset the password, the user object is no longer
    // available, and the user needs to login again.
    this.authService.loadUser().then((user) => {
      if (user) {
        // user has come back after edit profile.
        this.authService.loginSilent().then((u) => {
          this.user = u;
        });
      } else {
        // user has come back after reset password and need to login again.
        this.authService.loginRedirect();
      }
    });
  }

That’s pretty much it. Feel free to reach out if you have any questions.

Happy Coding.

References

oidc-client-js github wiki page

Tutorial: Create user flows in Azure Active Directory B2C

User flow versions in Azure Active Directory B2C

No comments yet