The Forgot password link of my Azure b2c login page sometimes redirect back to the login page. It redirects back to the login page in about 75% of the times I click it, and otherwise successfully to the page for changing password.
Here is my AuthenticationService:
export class AuthenticationService {
private id_token: string;
private access_token: string;
private applicationSettings: ApplicationSettings;
private authority: string;
clientApplication: UserAgentApplication;
jwtHelper: JwtHelper;
constructor(private settingsProvider: SettingsProvider) {
this.applicationSettings = settingsProvider.configuration;
this.authority = this.getAuthority();
this.jwtHelper = new JwtHelper();
this.clientApplication = new Msal.UserAgentApplication(
this.applicationSettings.clientID,
this.authority,
(errorDesc: any, token: any, error: any, tokenType: any) => {
this.logonCallback.call(this, errorDesc, token, error, tokenType);
},
this.applicationSettings.clientOptions
);
}
login(): void {
this.clientApplication.loginRedirect(
this.applicationSettings.b2cScopes);
}
loginPopup(): void {
var storedThis = this;
this.clientApplication.loginPopup(this.applicationSettings.b2cScopes)
.then((idToken) => {
this.id_token = idToken;
console.log("ID token:", idToken);
this.getAccessToken(this.applicationSettings.b2cScopes)
.catch((reason) => {
console.log('Unable to acquire token after login:', reason);
storedThis.logout();
});
}, function (error) {
console.log(error);
});
}
getAccessToken(scopes: string[]): Promise<string> {
var storedThis = this;
if(this.access_token) {
return new Promise((resolve, reject) => {
resolve(this.access_token)
});
}
let tokenPromise = this.clientApplication.acquireTokenSilent(scopes);
tokenPromise.then((token) => {
this.access_token = token;
console.log("Access token:", token);
});
tokenPromise.catch((reason) => {
this.clientApplication.acquireTokenPopup(scopes)
.then((token) => {
this.access_token = token;
console.log("Access token:", token);
}, function (error) {
console.log('Unable to acquire token using popup:', error);
storedThis.logout();
});
});
return tokenPromise;
}
logout(): void {
sessionStorage.removeItem('customerId');
sessionStorage.removeItem('customerIsActive');
this.clientApplication.logout();
};
isAuthenticated(): boolean {
let user = this.clientApplication.getUser();
return user !== null;
}
getUser() {
let user = this.clientApplication.getUser();
return user;
}
getB2cScopes() {
return this.applicationSettings.b2cScopes;
}
// Called after loginRedirect or acquireTokenPopup
private logonCallback(errorDesc: any, token: any, error: any, tokenType: any) {
// Password reset functionality
if (errorDesc) {
if (errorDesc.indexOf('AADB2C90118') > -1) {
localStorage.removeItem('theme');
this.clientApplication = new Msal.UserAgentApplication(
this.applicationSettings.clientID,
this.getPasswordResetAuthority(),
this.passwordResetCallback,
{
"redirectUri": this.applicationSettings.baseUrl + "/login"
}
);
this.login();
}
}
// Redirect to previous page functionality
var loginRedirectPath = sessionStorage.getItem('loginRedirectPath');
if (loginRedirectPath != null) {
sessionStorage.removeItem('loginRedirectPath');
window.location.replace(
this.settingsProvider.configuration.clientOptions.redirectUri + loginRedirectPath);
return;
}
// Get access token
if (!errorDesc || errorDesc.indexOf('AADB2C90118') == -1) {
console.log("ErrorNr: AADB2C90118");
this.getAccessToken(this.applicationSettings.b2cScopes)
.catch((reason) => {
console.log('Unable to acquire token after login:', reason);
});
}
}
getAuthority() {
return this.applicationSettings.b2cDomain + "/tfp/" +
this.applicationSettings.tenant + "/" +
this.applicationSettings.signUpSignInPolicy;
}
getPasswordResetAuthority() {
return this.applicationSettings.b2cDomain + "/tfp/" +
this.applicationSettings.tenant + "/" +
this.applicationSettings.passwordResetPolicy;
}
passwordResetCallback() {
this.logout();
}
}
Here is my AuthGuard:
export class AuthGuard implements CanActivate {
constructor(private authenticationService: AuthenticationService, private router: Router, private themeProvider: ThemeProvider) { }
canActivate(): any {
console.log('auth gaurd');
let userIsAuthenticated = this.authenticationService.isAuthenticated();
if (userIsAuthenticated) {
return true;
}
this.authenticationService.login();
return false;
}
}
The AuthGuard is used like this in the Routes in app.module:
{ path: '', canActivate: [AuthGuard], children: [ ...
Here is my configurations:
{
"tenant": "XXXXX.onmicrosoft.com",
"clientID": "XXXXX",
"signUpSignInPolicy": "B2C_1_Sign_Up_or_In",
"passwordResetPolicy": "B2C_1_Password_Reset_Policy",
"baseUrl": "http://localhost:4200",
"b2cScopes": [
"XXXXX"
],
"clientOptions": {
"redirectUri": "http://localhost:4200",
"postLogoutRedirectUri": "http://localhost:4200",
"validateAuthority": true,
"cacheLocation": "sessionStorage"
},
"b2cDomain": "https://login.microsoftonline.com"
}
I solved the issue. Since the user is not loged in when changing the password, my AuthGuard will try to run the login function. To solve this I added a note into session storage when getting the reset password error code, like this:
if (errorDesc.indexOf('AADB2C90118') > -1) {
...
sessionStorage.setItem('changePassword', 'true'); // Added this line
...
Then I checked for this note in my AuthGuard. If the note is set, then I do not want to run the login function, see below.
var changePassword = sessionStorage.getItem("changePassword");
if (changePassword == null)
this.authenticationService.login();
else
sessionStorage.removeItem("changePassword");
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.