angularazure-ad-b2cangular-oauth2-oidc

angular-oauth2-oidc forgot password flow


I am setting up B2C on my Angular (8) app with angular-oauth2-oidc. I have a sign in and a sign out policy and I have managed correctly to set up the angular-oauth2-oidc service. At the moment I am using the standard Microsoft login page which contains a Forgot Password link. I have created the flow for the Forgot Password in B2C, but I am struggling to integrate it in angular-oauth2-oidc. When I click the Forgot Password link, B2C throws an error "AADB2C90118"; to make sure that the flow is correct I have tested the flow creating an AuthConfig file such the one that I have created for the sign in policy; just with the Forgot Password flow information (in this case the users clicks a button and is redirected to the Forgot Password issuer) - and it works.

Is there any variable in the AuthConfig file that can be set as the Forgot Password endpoint or any way that can handle this issue?


Solution

  • I managed to get it working by following a suggestion from the creator of the angular-oauth2-oidc library.

    First, I created an OAuthErrorEventParams interface I can cast my OAuthErrorEvent.params to:

    export interface OAuthErrorEventParams {
       error: string;
       error_description: string;
       state: string;
     }
    

    I then created this constant to represent my RedirectUrl to redirect to the password reset flow:

    export const PasswordResetUrl = 'https://[tenantname].b2clogin.com/[tenantname].onmicrosoft.com/oauth2/v2.0/authorize?' +
        'p=[PasswordResetFlowName]' +
        '&client_id=' + authConfig.clientId +
        '&nonce=defaultNonce' +
        '&redirect_uri=' + window.location.origin + '/index.html' +
        '&scope=openid' +
        '&response_type=id_token' +
        '&prompt=login';
    

    And then finally in my component that handles the setup and config of the Auth service, I added the below:

    constructor(private oauthService: OAuthService) {
         this.configure();
         this.oauthService.events.subscribe(e => {
           if (e instanceof OAuthErrorEvent) {
             const parm = e.params as OAuthErrorEventParams;
             if (parm.error === 'access_denied' && parm.error_description.includes('AADB2C90118')) {
               // redirect to forgot password flow
               window.location.href = PasswordResetUrl;
             } else if (parm.error === 'access_denied' && parm.error_description.includes('AADB2C90091')) {
               // user has cancelled out of password reset
               this.oauthService.initLoginFlow();
             }
           }
         });
         this.oauthService.tryLoginImplicitFlow();
       }
    

    I really hope this helps someone because I had a hell of a time finding a solution to this prior to landing up here.