To authenticate users in my Angular app i use access tokens with expiry time X seconds and refresh tokens that can be used to prolong the auth for another X seconds.
So the flow is this:
My problem is this:
400 Bad Request - Invalid refresh token
for the subsequent requests, since it considers them used.Does anyone have a good idea how this could be solved? How does one synchronize things across tabs/windows? I have a couple of ideas but they all seem a bit far fetched:
400 Bad Request
, then retry in a little while (or check if there is a valid updated token already).Refresh tokens never expire, unless revoked by the user.
Access token and refresh token shouldn't be stored in the local/session storage, because they are not a place for any sensitive data. Hence I would store the access token in a httpOnly cookie (even though there is CSRF) and I need it for most of my requests to the Resource Server anyway.
To refresh the access token, select the Refresh access token API call within the Authorization folder of the Postman collection. Next, click the Send button to request a new access_token .
The API returns a short-lived token (JWT), which expires in 15 minutes, and in HTTP cookies, the refresh token expires in 7 days. JWT is currently used for accessing secure ways on API, whereas a refresh token generates another new JWT access token when it expires or even before.
dont set timer , add interceptor and catch error and if you got 401 error , do your refresh token flow and then repeat failed request with new token
intercept(request: HttpRequest<any>, next: HttpHandler):
Observable<HttpEvent<any>> {
return next.handle(request).pipe(
catchError((error: HttpErrorResponse) => {
if (error.status == 401) {
return this.refreshToken(request, next);
}
}
return throwError(error);
})
);
private refreshingInProgress: boolean = false;
private accessTokenSubject: BehaviorSubject<any> = new BehaviorSubject<any>(null);
private refreshToken(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
if (!this.refreshingInProgress) {
this.refreshingInProgress = true;
this.accessTokenSubject.next(null);
return this.authenticationService.refreshToken().pipe(
switchMap((res: any) => {
this.refreshingInProgress = false;
this.accessTokenSubject.next(res);
// repeat failed request with new token
return next.handle(this.addToken(request, res));
})
);
} else {
// wait while getting new token
return this.accessTokenSubject.pipe(
filter((token) => token !== null),
take(1),
switchMap((token) => {
// repeat failed request with new token
return next.handle(this.addToken(request, token));
})
);
}
}
private addToken(request: HttpRequest<any>, token: Credentials) {
return request.clone({
setHeaders: {
Authorization: `Bearer ${token.access_token}`,
},
});
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With