Last active
September 9, 2020 06:36
-
-
Save tobbbe/08e01db92c32346b226333a3f952df22 to your computer and use it in GitHub Desktop.
Angular interceptor token refresh token user service. Thanks to: https://www.intertech.com/Blog/angular-4-tutorial-handling-refresh-token-with-new-httpinterceptor/
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Injectable, Injector } from '@angular/core'; | |
import { HttpErrorResponse, HttpHandler, HttpInterceptor, HttpRequest, HttpEvent, HttpClient, HttpHeaders } from '@angular/common/http'; | |
import { Observable } from 'rxjs/Observable'; | |
import { ErrorObservable } from 'rxjs/Observable/ErrorObservable'; | |
import { EmptyObservable } from 'rxjs/Observable/EmptyObservable'; | |
import { BehaviorSubject } from 'rxjs/BehaviorSubject'; | |
import { catchError, filter, take, switchMap, finalize } from "rxjs/operators"; | |
import { APIURL } from "../app/constants"; | |
import { UserService } from "./user/user.provider"; | |
@Injectable() | |
export class TokenInterceptor implements HttpInterceptor { | |
isRefreshingToken: boolean = false; | |
tokenSubject: BehaviorSubject<string> = new BehaviorSubject<string>(null); | |
constructor(private injector: Injector, private userService: UserService) { } | |
private setAuthHeader(request) { | |
return request.clone({ url: APIURL + request.url, setHeaders: { Authorization: `Bearer ${this.userService.token}` } }); | |
} | |
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> { | |
return next.handle(this.setAuthHeader(request)) | |
.pipe( | |
catchError((error, ca) => { | |
if (error instanceof HttpErrorResponse) { | |
switch ((<HttpErrorResponse>error).status) { | |
case 401: | |
return this.handle401Error(request, next) | |
default: | |
return ErrorObservable.create(error); | |
} | |
} else { | |
return ErrorObservable.create(error); | |
} | |
}) | |
) | |
} | |
handle401Error(req: HttpRequest<any>, next: HttpHandler) { | |
if (!this.isRefreshingToken) { | |
this.isRefreshingToken = true; | |
// Reset here so that the following requests wait until the token | |
// comes back from the refreshToken call. | |
this.tokenSubject.next(null); | |
const http = this.injector.get(HttpClient); | |
return http.get('/auth/RefreshToken', { headers: new HttpHeaders().set('Authorization', `Bearer ${this.userService.token}`) }) | |
.pipe( | |
switchMap((newToken: string) => { | |
if (newToken) { | |
this.userService.setToken(newToken) | |
this.tokenSubject.next(newToken) | |
return next.handle(this.setAuthHeader(req)); | |
} | |
// If we don't get a new token, we are in trouble so logout. | |
this.userService.logout() | |
console.log('Could not refresh token 1') | |
return EmptyObservable.create(); | |
}), | |
catchError(error => { | |
// If there is an exception calling 'refreshToken', bad news so logout. | |
this.userService.logout() | |
console.log('Could not refresh token 2') | |
return EmptyObservable.create(); | |
}), | |
finalize(() => { | |
this.isRefreshingToken = false; | |
}) | |
) | |
} else { | |
return this.tokenSubject | |
.pipe( | |
filter(token => token != null), | |
take(1), | |
switchMap(token => { | |
return next.handle(this.setAuthHeader(req)); | |
}) | |
) | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Injectable, Injector } from '@angular/core'; | |
import { Subject } from "rxjs/Subject"; | |
import { HttpClient } from "@angular/common/http"; | |
@Injectable() | |
export class UserService { | |
token: string | |
events: Subject<string> = new Subject<string>() | |
constructor(private injector: Injector) { | |
this.token = localStorage.getItem('token'); | |
} | |
init() { | |
if (!this.token) return Promise.reject('No token'); | |
return Promise.resolve(); | |
} | |
setToken(token: string) { | |
this.token = token; | |
localStorage.setItem('token', token) | |
} | |
logout() { | |
const http = this.injector.get(HttpClient); | |
http.get(`/auth/Logout?token=${this.token}`).subscribe() | |
this.token = null; | |
localStorage.clear() | |
this.events.next('logout') | |
} | |
} |
Fixed. The path is wrong. It should be
from “rxjs/observable/EmptyObservable“;
not logging out on refresh token failure. when refresh token service returns 401, control is not going to error block.
Hi, Do you have complete code for 'refresh token on 401 error' implementation for Angular 5? When i tried i was getting into cyclic errors.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Do I need to add anything in system-config.ts for below error ?