react-aad: Forgot password seems to be unimplemented or missing from documentation

Please provide us with the following information:

This issue is for a: (mark with an x)

- [ ] bug report -> please search issues before submitting
- [ ] feature request
- [X] documentation issue or request
- [ ] regression (a behavior that used to work and stopped in a new release)

Minimal steps to reproduce

Configure Azure with a signin sign up user flow Configure Azure with a Password reset user flow Look for documentation on where to set the forgot password user flow

Results: Nothing found

Any log messages given by the failure

Not applicable

Expected/desired behavior

I would expecty full documentation on how to configure

OS and Version?

Not applicable

Versions

0.4.9

Mention any other details that might be useful

I briefly scanned through the code and couldn’t see anything that looked applicable to the forgot password user flow, I recognize I might just not have looked hard enough, but regardless. I think this should be documented (or implemented if it’s not)

About this issue

  • Original URL
  • State: open
  • Created 5 years ago
  • Reactions: 1
  • Comments: 15 (1 by maintainers)

Most upvoted comments

I used the functions exposed by MsalAuthProvider.

// authProvider.js
import { MsalAuthProvider } from 'react-aad-msal';

// Msal Configurations
const config = { ... }

// Authentication Parameters
const authenticationParameters = { ... }

// Options
const options = { ... }

// Forgot Password Handler
function handleForgotPassword(error) {
  if (error && error.errorMessage.indexOf('AADB2C90118') > -1) {
    authProvider.setAuthenticationParameters ({authority: <PASSWORD RESET AUTHORITY>})
    authProvider.login()
  }
}

const authProvider = new MsalAuthProvider(config, authenticationParameters, options)
authProvider.registerErrorHandler(handleForgotPassword)

export default authProvider
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { AzureAD } from 'react-aad-msal';

import App from './App';
import authProvider from './authProvider';

authProvider.setAuthenticationParameters ({authority: <SISO AUTHORITY>})
ReactDOM.render(
  <AzureAD provider={authProvider} >
    <App />
  </AzureAD>,
  document.getElementById('root'),
);

My solution is just to dig into the exposed MSAL functions and do the following:

authProvider.handleRedirectCallback((error, response) => {
  if (error && error.errorMessage.indexOf('AADB2C90118') > -1) {
    authProvider.loginRedirect({
      authority: 'https://<tenant>.b2clogin.com/<tenant>.onmicrosoft.com/B2C_1A_PasswordReset',
      redirectUri: window.location.origin,
      extraQueryParameters: {
        // eslint-disable-next-line @typescript-eslint/camelcase
        ui_locales: 'de',
      },
    });
  }
});

I think my sample should be extended to catch the returned token after Password Reset to prevent a second login prompt to the user. Maybe I’ll have time to look at that within the next few days.

Hope that helps.

I just ended up writing this code to hack my way around resetPassword handling for the redirect loginType:

  if (window.location.href.indexOf('AADB2C90118') > -1) {
    window.localStorage.setItem('resetPassword', true)
    providerFactory = new MsalAuthProvider(
      siteData.msal.config,
      siteData.msal.authenticationParameters,
      LoginType.Redirect
    );
  } else if (window.localStorage.getItem('resetPassword')) {
    window.localStorage.removeItem('resetPassword');
    const config = { ...siteData.msal.config, auth: { ...siteData.msal.config.auth, authority: "https://sbnkfm.b2clogin.com/tfp/sbnkfm.onmicrosoft.com/B2C_1_pwd" } };
    providerFactory = new MsalAuthProvider(
      config,
      siteData.msal.authenticationParameters,
      LoginType.Redirect
    );
  } else {
    providerFactory = new MsalAuthProvider(
      siteData.msal.config,
      siteData.msal.authenticationParameters,
      LoginType.Redirect
    );
  }

Hope this solution might help some people till the library gets a fix

  1. When forgot password is clicked at your app use authProvider.registerErrorHandler and change authority to reset password policy by using authProvider.setAuthenticationParameters({ authority: resetPolicyURL}).
    authProvider.registerErrorHandler(error => {
        if ( error.errorMessage.indexOf('AADB2C90091') > -1 ) {
          // reset authority to reset password policy
        }
        if ( error.errorMessage.indexOf('AADB2C90077') > -1 ) { // may be may not be needed
          // reset authority to signin policy
        }
        if (error.errorCode === 'token_renewal_error') {
          // reset authority to signin policy
          authProvider.signin() // if you want user to directly go to sign in
          window.location.reload() // if you want user to click sign in manually by clicking
        }
     })
    
  2. Have the below as your configuration.
     cache: {
         ...,
         storeAuthStateInCookie: true // to be able to clear cookies later
     }
    
  3. After renewal token fail, handle in loginSuccess and check for the payload,
    payload: {
        account: {
             idToken: {
                 tfp: 'resetpasswordpolicy'
             }
        }
    }
    
    

if tfp satisfies resetpasswordpolicy based token, then use authProvider and make a call authProvider.logout()

  1. Now on click of login or with user action clear all cookies or at least msal*. This is needed otherwise after login you will get 431 error as cookies size will increase because of more iframe requests failed.
  2. Go to login and login with proper username and password and it will work.
Restriction:
  • Chrome (not incognito) will work for this
  • Firefox, Edge, Chrome (incognito) - Enable to Allow all third party cookies
  • Safari - Disable Prevent cross-site tracking

Thank you very much for your workaround @Premkumar-Shanmugam, it works perfectly.

I just wish we had a way to do it ‘natively’ without having so many redirects back and forth…

Has anyone found a workaround for this issue when using the redirect flow. When the reset password flow is finished on the azure side, it redirects back to my React app

  • with /b2c_1_passwordreset/oauth2/v2.0/authorize
  • but it should be /b2c_1_signin/oauth2/v2.0/authorize

causing the refresh token iframe to fail with ` in a frame because it set ‘X-Frame-Options’ to ‘deny’.

I ended up with following solution,

ReactDOM.render(
  <Router>
       <Route exact path="/" render={(): JSX.Element => (
	    // Login/SignUp
	    <AzureAD provider={authProvider.authProviderWithSignUpSignInPolicy}>
	           {(props: IAzureADFunctionProps): JSX.Element => {
			if (props.error && props.error.errorMessage.search("AADB2C90118") !== -1) {
		             // Forgot password
                             return <AzureAD forceLogin provider={authProvider.authProviderWithPassResetPolicy} />;
                        }

                    return <App {...props} />;
                   }}
            </AzureAD>
      )} />
</Router>,
document.getElementById("root"));