I'm encountering an issue with the angular-auth-oidc-client package in my Angular 14 application regarding the behavior of auto-login when opening a new tab. While the authentication process itself seems to be functioning correctly, there's a problem with the redirection behavior after auto-login.
Library: angular-auth-oidc-client
Scenario:
User is logged in on the main tab of the application. User opens a new tab and navigates directly to a specific page, such as "my-account". Expected Behavior: After auto-login, the user should be redirected to the requested page, in this case, "my-account".
Actual Behavior: Instead of being redirected to the requested page ("my-account"), the application redirects the user back to the initial page (e.g., the home page).
This behavior is not ideal for the user experience, as it disrupts the intended flow of navigation within the application.
*- Question:- *
Any insights or suggestions would be greatly appreciated. Thank you!
I've tried implementing the AutoLoginPartialRoutesGuard to handle the redirection, but it hasn't resolved the issue. I'm seeking assistance on how to properly configure the AutoLoginPartialRoutesGuard or any other approach to ensure that users are redirected to the intended page after auto-login, particularly when opening a new tab.
Route File
RouterModule.forRoot([
{
path: '',
canActivate: [AuthorizationGuard],
component: MainComponent,
children: [
{
path: '',
redirectTo: 'overview',
pathMatch: 'full'
},
{
path: 'orders',
loadChildren: () => import('./modules/orders/orders.module').then(m => m.OrdersModule),
canActivate: [AutoLoginPartialRoutesGuard],
},
{
path: '**',
redirectTo: ''
}
]
}
], {
useHash: environment.hashRouting,
scrollPositionRestoration: 'enabled'
})
Auth Config
export const httpLoaderFactory = () => {
const authOptions$: Observable<OpenIdConfiguration> = config$.pipe(
map((authOptions: AuthOptions) => {
return {
authority: authOptions.authEndpoint,
redirectUrl: 'https://localhost:3000',
postLogoutRedirectUri: 'https://localhost:3000',
clientId: authOptions.spaClientId,
scope: 'openid profile offline_access',
responseType: 'code',
secureRoutes: [authOptions.apiEndpoint, authOptions.authEndpoint],
silentRenew: true,
useRefreshToken: true,
ignoreNonceAfterRefresh: true,
automaticSilentRenew: true,
disableIdTokenValidation: true,
autoUserInfo: false
} as OpenIdConfiguration;
})
);
return new StsConfigHttpLoader(authOptions$);
};
Auth Guard
export class AuthorizationGuard implements CanActivate {
constructor(private authService: AuthService) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | UrlTree | Observable<boolean | UrlTree> | Promise<boolean | UrlTree> {
return this.authService.isAuthorized().pipe(
map(isAuthorized => {
if (!isAuthorized) this.authService.authorize();
return isAuthorized;
})
);
}
}
To resolve the issue you're encountering, there are two approaches you can take:
1. Use of AutoLoginPartialRoutesGuard:
This involves utilizing AutoLoginPartialRoutesGuard from angular-auth-oidc-client in two places. Firstly, you need to include it in your routes as shown above. Secondly, you need to use it as a guard within your Angular application.
import { AutoLoginPartialRoutesGuard } from 'angular-auth-oidc-client';
constructor(
.....
private autoLoginPartialRoutesGuard: AutoLoginPartialRoutesGuard
.....) { }
canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): boolean | UrlTree | Observable<boolean | UrlTree> | Promise < boolean | UrlTree > {
return this.authService.isAuthorized().pipe(
switchMap(isAuthorized => {
return this.autoLoginPartialRoutesGuard.canActivate(route, state).pipe(
map(() => {
if (!isAuthorized) this.authService.authorize();
return isAuthorized;
})
);
})
)}
This implementation will address your issue.
2. Use of custom storage from the library:
By default, the package is configured to use session storage, which might not retain the state across tabs. Instead, you can opt to use local storage to resolve the issue. To do this, you need to create a service as outlined in the documentation.
Example :
import { Injectable } from "@angular/core";
import { AbstractSecurityStorage } from "angular-auth-oidc-client";
@Injectable()
export class LocalStorageManagerService implements AbstractSecurityStorage {
read(key: string) {
return localStorage.getItem(key);
}
write(key: string, value: any): void {
localStorage.setItem(key, value);
}
remove(key: string): void {
localStorage.removeItem(key);
}
clear(): void {
localStorage.clear();
}
}
You then need to include this service in your module's providers.
providers: [
{
provide: AbstractSecurityStorage,
useClass: LocalStorageManagerService
},
.....
]
Implementing this solution will help resolve your issue.
Thanks for reading