4

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?

simon90
  • 123
  • 1
  • 8

2 Answers2

6

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.

Ruben Szekér
  • 1,065
  • 1
  • 10
  • 21
Captain Kenpachi
  • 6,960
  • 7
  • 47
  • 68
  • 1
    Thank you! For the moment I was going around the problem using a custom login page and redirecting the Forgot Password link to the correct one, but I'll definitely use this other solution – simon90 Apr 06 '20 at 13:59
  • Glad I could help, bro. – Captain Kenpachi Apr 07 '20 at 17:24
  • 1
    This solution worked for me. I only had to tweak it slightly. Using `window.location.origin` did not work for me (I have 3 different reply URLs) so I used the full URLs instead. You can copy/paste these URLs from Azure B2C when testing the user flow. – Ruben Szekér Jan 29 '21 at 09:48
1

For those who have this problem with the Code Flow (NO IMPLICIT GRANT), we have to edit the PasswordResetUrl like this:

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=code' +
'&prompt=login' +
'&code_challenge=##################&code_challenge_method=S256';
andrea.spot.
  • 496
  • 4
  • 9