angularauthenticationhttp-redirectangular-auth-oidc-client

Angular-auth-oidc-client: Auto-login Redirects to Initial Page Instead of Requested Page in New Tab


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:- *

  1. How can I effectively use the AutoLoginPartialRoutesGuard to ensure correct redirection after auto-login?
  2. Are there any alternative approaches or configurations I should consider to address this issue?

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;
      })
    );
  }
}

Solution

  • 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