2
votes

I have created an authentication service in which I check the presence of access token in a local storage. For that I have created an observable which calls a hasValidAccessToken function. The function emits the boolean value.

I make the subscription to that observable in app-component. The issue is I am not able to unsubscribe the subscription in app-component because it never gets destroyed.

authentication.service.ts

 public isAuthenticatedSubject: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(this.hasValidAccessToken());
    public isAuthenticated$: Observable<boolean>;

 isTokenExpired(): boolean {
        const expiresAt = localStorage.getItem("expires_at");
        const now = new Date();
        if (
            expiresAt &&
            parseInt(expiresAt, 10) < Math.floor(now.getTime() / 1000)
        ) {
            return false;
        }
        return true;
    }

    hasValidAccessToken(): boolean {
        if (this.hasAccessToken()) {
            return this.isTokenExpired();
        }
        return false;
    }

    hasAccessToken(): boolean {
        return !!localStorage.getItem("access_token");
    }

    decodeToken(token: string) {
        if (token) {
            return jwt_decode(token);
        }
    }

app.component.ts

this.isAuthenticatedSubscription = this.oauthService.isAuthenticated$.subscribe(
                data => {
                    if (data) {
                        this.router.navigate(["home"]);
                    } else {
                        this.router.navigate(["login"], {
                            state: { data: "session has been expired" }
                        });
                    }
                }
            );
2
Means you are not able to do this.isAuthenticatedSubscription.unsubscribe()? what error do you get? - Vivek Doshi
You should create AuthenticationGuard for that purpose. And then guard your routes with canActivate. Angular Authentication using Guards - Dino
@VivekDoshi app component not destroy until the close the browser or shut down the app. so where should i use this.isAuthenticatedSubscription.unsubscribe(). - ankit

2 Answers

3
votes

You should never unsubscribe from that observable. You are basically recreating the Authentication Guard. Imagine if you do unsubscribe from it, and at one point in your application you lose your authentication token (Logout, or it expires...). Since you've unsubscribed from it, you will still be able to browse the application as this code will never trigger:

 else {
         this.router.navigate(["login"], {
             state: { data: "session has been expired" }
         });
      }

My suggestion is to replace the logic by creating the Authentication Guard I mentioned before. That way you will be able to secure your routes with canActivate, which is also the best practice.

3
votes

You can use take to make your Observable complete after a set number of emissions.

this.isAuthenticatedSubscription = this.oauthService.isAuthenticated$
    .pipe(
        take(1)
    )
    .subscribe(
        data => {
            if (data) {
                this.router.navigate(["home"]);
            } else {
                this.router.navigate(["login"], {
                    state: { data: "session has been expired" }
                });
            }
        }
    );

Edit: Although this would solve your question, @Dino is right, you shouldn't be unsubscribing from that observable as the login state of your application depends on it. You should rather move this logic to an AuthGuard.