I am seeking relevant advice to address my specific need:
In my Angular application, I have implemented a jwt-based authentication system. After obtaining a new token and refresh token, I have set up a setTimeout function to ensure the token is refreshed before it expires. However, I also intentionally refresh the token when bootstrapping the app in my AppComponent, which has led to an issue.
The problem arises when retrieving user information from the jwt during app bootstrap. Due to the timing of token storage after component display, the app ends up fetching user details from the previous token instead of the newly generated one.
While considering using resolvers, the drawback is that it would result in triggering two refresh token queries - one in the AppComponent and another inside the resolver, which is not the desired behavior.
So, here is a snippet from my AppComponent:
ngOnInit() {
this.refreshToken();
...
}
private refreshToken() {
this.authSvc.refreshToken().pipe(
untilDestroyed(this),
catchError(error => {
if (error.status === 401) {
this.router.navigate(['/login']);
}
return of();
})
).subscribe();
}
And here is part of the AuthService:
get user(): User | null {
const token = localStorage.getItem('token');
return token ? this.jwtHelper.decodeToken(token) : null;
}
refreshToken(): Observable<LoginResponse> {
return this.http.post<LoginResponse>(
`${environment.apiUrl}/token/refresh`,
{refresh_token: localStorage.getItem('refresh_token')}, this.CONTEXT
).pipe(
tap((res: LoginResponse) => this.storeTokens(res as LoginSuccess))
);
}
storeTokens(data: LoginSuccess): void {
localStorage.setItem('token', data.token);
localStorage.setItem('refresh_token', data.refresh_token);
this.scheduleTokenRefresh(data.token);
}
Furthermore, I have a component where I require user data:
export class HomeComponent implements OnInit {
user!: User | null;
constructor(private authSvc: AuthService) {
}
ngOnInit() {
this.user = this.authSvc.user;
}
The challenge lies in Home component being displayed before storeTokens method is called, resulting in potential mismatch between user data on the backend and the token used by HomeComponent. I have explored using a resolver but it necessitates calling refreshToken again, which does not align with my requirements of keeping the refreshToken logic within the AppComponent without duplicate calls.
Is there a more suitable solution for this scenario?