How Creat Routing after Authentification with angular-oauth2-oidc on curent route

530 Views Asked by At

I a have stack Angular 13 with angular-oauth2-oidc: 13.0.1 and angular-oauth2-oidc-jwks: 13.0.1 for OAuth2.

I'm trying to just redirect the user to the current route before redirecting the login URI.

So currently I'm in implicitflow and I want save the route before the authentication so that after the token received I redirect it to the initial call url.

And my current problem and that can't save the right URL before authentication


@Injectable({
  providedIn: "root",
})
export class InitialAuthService {
  private jwtHelper: JwtHelperService = new JwtHelperService();

  private isAuthenticatedSubject = new BehaviorSubject<boolean>(false);
  private isAuthenticated = this.isAuthenticatedSubject.asObservable();

  // tslint:disable-next-line:variable-name
  private _decodedAccessToken: any;
  // tslint:disable-next-line:variable-name
  private _decodedIDToken: any;

  get decodedAccessToken() {
    return this._decodedAccessToken;
  }
  get decodedIDToken() {
    return this._decodedIDToken;
  }

  get profile() {
    return this.oauthService.loadUserProfile();
  }

  constructor(
    private oauthService: OAuthService,
    private authConfig: AuthConfig,
    public router: Router,
    public activeRoute: ActivatedRoute,
    private authService: AuthService,
  ) {
  }

  async initAuth(): Promise<any> {
    
    const currenturl = this.activeRoute.snapshot.url;
        return new Promise<void>((resolveFn, rejectFn) => {

          this.oauthService.configure(this.authConfig);
          this.oauthService.setStorage(localStorage);
          this.oauthService.tokenValidationHandler = new JwksValidationHandler();

          // subscribe to token events
          this.oauthService.events
            .pipe(filter((e: OAuthEvent) => e.type === "token_received"))
            .subscribe(({ type }) => {
              console.debug("token_received");
              this.handleNewToken();
              console.debug("before");
              console.debug(currenturl);
              this.router.navigate([currenturl]);
              console.debug("after");
            });

          this.oauthService.events
            .pipe(filter((e: any) => e.type === "token_expires"))
            .subscribe(({ type }) => {
              console.debug("token_expires");
              this.logoutSession();
            });

          this.oauthService.events
            .pipe(filter((e: any) => e.type === "token_error"))
            .subscribe(({ type }) => {
              console.debug("token_error");
              this.logoutSession();
            });

          this.oauthService.events
            .subscribe(_ => {
              this.isAuthenticatedSubject.next(this.oauthService.hasValidAccessToken());
            });


          this.oauthService.loadDiscoveryDocumentAndLogin().then(
            (isLoggedIn) => {
              if (isLoggedIn) {
                resolveFn();
              } else {
                console.debug("initImplicitFlow");
                this.oauthService.initImplicitFlow();
                rejectFn();
              }
            },
            (error: { status: number; }) => {
              console.log({ error });
              if (error.status === 400) {
                location.reload();
              }
            }
          );
        });
      });
  }


  private handleNewToken() {

    this._decodedAccessToken = this.jwtHelper.decodeToken(
      this.oauthService.getAccessToken()
    );

    this._decodedIDToken = this.jwtHelper.decodeToken(
      this.oauthService.getIdToken()
    );

    this.authService.login();
  }

  logoutSession() {
    console.debug("logout");
    this.oauthService.logOut();
    this.authService.logout();
  }


  isLogin(): Observable<boolean> {
    return this.isAuthenticated;
  }
}
1

There are 1 best solutions below

0
On

Good news: there's built in support on the OpenID protocol for this, and the library supports it. You can clone my sample repository, or more specifically check the two moving parts:

Here's the gist of both parts in code:

// Guard that passes the "intended" route to the library and thus the IDP via 'state'
canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot,
): Observable<boolean> {
    return this.authService.isDoneLoading$.pipe(
      filter(isDone => isDone),
      switchMap(_ => this.authService.isAuthenticated$),
      tap(isAuthenticated => isAuthenticated || this.authService.login(state.url)), // << !!
    );
}
// when booting the library and trying to login:
this.oauthService.loadDiscoveryDocumentAndTryLogin()
    // more logic here?
    .then(() => {
        if (this.oauthService.state && this.oauthService.state !== 'undefined' && this.oauthService.state !== 'null') {
          let stateUrl = this.oauthService.state;
          if (stateUrl.startsWith('/') === false) {
            stateUrl = decodeURIComponent(stateUrl);
          }
          console.log(`There was state of ${this.oauthService.state}, so we are sending you to: ${stateUrl}`);
          this.router.navigateByUrl(stateUrl);
        }
    })

Again, the sample repository you can clone and just fire up to see all this in action.