I've implemented http interceptor for new HttpClient and everything works fine, token is refreshed for single request, but if I try to access the route which lazy load data from two api's I received an error and my JWT token is blacklisted.
Laravel Backend Token Refresh Method:
public function refreshToken() {
$token = \JWTAuth::getToken();
if (! $token) {
return response()->json(["error" => 'Token is invalid'], 401);
}
try {
$refreshedToken = \JWTAuth::refresh($token);
$user = \JWTAuth::setToken($refreshedToken)->toUser();
} catch (JWTException $e) {
return response()->json(["error" => $e->getMessage()], 400);
}
return response()->json(["token" => $refreshedToken, "user" => $user], 200);
}
Angular Http Interceptor:
@Injectable()
export class RefreshTokenInterceptor implements HttpInterceptor {
constructor(private injector: Injector) { }
intercept(request: HttpRequest<any>, next: HttpHandler) : Observable<HttpEvent<any>> {
return next.handle(request).catch((errorResponse: HttpErrorResponse) => {
const error = (typeof errorResponse.error !== 'object') ? JSON.parse(errorResponse.error) : errorResponse;
if(errorResponse.status === 401 && error.error === 'token_expired') {
const http = this.injector.get(HttpClient);
let token = localStorage.getItem('token');
return http.post<any>(`${environment.apiBaseUrl}token/refresh`, {},
{headers: new HttpHeaders().set('Authorization', `Bearer ${token}`)})
.flatMap(data => {
localStorage.setItem('currentUser', JSON.stringify(data));
localStorage.setItem('token', data.token);
const cloneRequest = request.clone({setHeaders: {'Authorization': `Bearer ${data.token}`}});
return next.handle(cloneRequest);
});
}
return Observable.throw(errorResponse);
});
}
}
My Route which use resolvers:
{
path: '',
children: [ {
path: 'create',
component: CreateCarComponent,
resolve: {
subcategories: SubCategoriesResolver,
companies: CompaniesResolver
}
}]
}
Companies Resolver: (Car resolver is simmilar to this)
@Injectable()
export class CompaniesResolver implements Resolve<any> {
constructor(private _userService: UserService) {}
resolve(route: ActivatedRouteSnapshot) {
return this._userService.getCompaniesList();
}
}
User Service Method Example:
getUserCardsApi: string = "user/cars/all";
getCardsList() : Observable<any[]> {
return this._http.get(environment.apiBaseUrl + this.getUserCardsApi, this.jwtHeaders())
.catch(error => {
return Observable.throw(error);
});
}
Headers:
private jwtHeaders() {
let currentUser = JSON.parse(localStorage.getItem('currentUser'));
return {headers: new HttpHeaders().set('Authorization', 'Bearer ' + currentUser.token)}
}
}
Whenever I hit routes with more than 2 resolvers, first response I receive is correct and returns a refreshed token with user object and the next one after that right away returns token blacklisted. Could you please suggest what can be the issue, I've spent too much time on solving this (
Update 1:
What I noticed is that second refresh request is passing an old token rather than a new one thats why Laravel blacklisting a token