Angular2-jwt: Can anybody share their refresh token HTTP interceptor for V1.0?

Created on 26 Feb 2018  ·  4Comments  ·  Source: auth0/angular2-jwt

I was wondering if anybody has an example of how to refresh the token and retry HTTP calls using the http interceptor and angular2-jwt v1.0 for angular4+.

Thanks

stale

Most helpful comment

Here's my interceptor:

import { AuthToken } from '../../account/dto/auth-token';
import { AuthTokenRepository } from '../../account/repositories/auth-token.repository';
import { Injectable } from '@angular/core';
import {
    HttpClient,
    HttpErrorResponse,
    HttpEvent,
    HttpInterceptor,
    HttpHandler,
    HttpRequest,
    HttpResponse
} from '@angular/common/http';
import { Injector } from '@angular/core';
import { JwtHelper } from 'angular2-jwt';
import { Observable } from 'rxjs/Observable';
import { Router } from '@angular/router';
import { SlimLoadingBarService } from 'ng2-slim-loading-bar';
import { SocketService } from './socket.service';
import { Subscription } from 'rxjs/Subscription';
import { environment } from '../../../environments/environment';
import { global } from '../static/global';
import 'rxjs/add/operator/do';

@Injectable()
export class InterceptorService implements HttpInterceptor {
    private isUpdating = false;
    private jwtHelper: JwtHelper = new JwtHelper();
    private offsetSeconds = 3600;
    private subscriptions = new Array<Subscription>();

    constructor(
        private injector: Injector,
        private router: Router,
        private slimLoadingBarService: SlimLoadingBarService,
        private socketService: SocketService
    ) {}

    public intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        this.slimLoadingBarService.start();
        const token = localStorage.getItem(global.tokenName);

        if (request.url.startsWith(environment.baseUrl)) {
            request = request.clone({
                setHeaders: {
                    Authorization: token != null ? token : '',
                    'Content-Type': 'application/json'
                }
            });
        }

        return next.handle(request).do(
            (event: HttpEvent<any>) => {
                if (event instanceof HttpResponse) {
                    this.slimLoadingBarService.complete();
                    if (!request.url.includes('auth-tokens')) { // my api endpoint to avoid to trigger the interceptor when I refresh the token.
                        try {
                            const expirationLeft = this.jwtHelper.getTokenExpirationDate(token).getTime() - Date.now();
                            if (expirationLeft > 0 ) {
                                if (expirationLeft < (this.offsetSeconds * 1000) && !this.isUpdating) {
                                    this.updateAuthToken();
                                }
                            }
                        } catch (e) {}
                    }
                }
            },
            (error: any) => {
                this.slimLoadingBarService.complete();
                if (error instanceof HttpErrorResponse) {
                    if (error.status === 401) {
                        localStorage.clear();
                        this.socketService.close();
                        for (const sub of this.subscriptions) {
                            sub.unsubscribe();
                        }
                        this.router.navigateByUrl('/sign-in');
                    }
                }
            }
        );
    }

     /**
     * Updates the token if it will expire and the current user is navigating.
     */
    private updateAuthToken(): void {
        this.isUpdating = true;
        const authTokenRepository = this.injector.get(AuthTokenRepository);
        this.subscriptions.push(authTokenRepository.getAuthTokenUpdate().subscribe(
            (authToken: AuthToken) => {
                localStorage.setItem(global.tokenName, authToken.value);
                this.isUpdating = false;
            }
        ));
    }
}

See #18224

All 4 comments

Here's my interceptor:

import { AuthToken } from '../../account/dto/auth-token';
import { AuthTokenRepository } from '../../account/repositories/auth-token.repository';
import { Injectable } from '@angular/core';
import {
    HttpClient,
    HttpErrorResponse,
    HttpEvent,
    HttpInterceptor,
    HttpHandler,
    HttpRequest,
    HttpResponse
} from '@angular/common/http';
import { Injector } from '@angular/core';
import { JwtHelper } from 'angular2-jwt';
import { Observable } from 'rxjs/Observable';
import { Router } from '@angular/router';
import { SlimLoadingBarService } from 'ng2-slim-loading-bar';
import { SocketService } from './socket.service';
import { Subscription } from 'rxjs/Subscription';
import { environment } from '../../../environments/environment';
import { global } from '../static/global';
import 'rxjs/add/operator/do';

@Injectable()
export class InterceptorService implements HttpInterceptor {
    private isUpdating = false;
    private jwtHelper: JwtHelper = new JwtHelper();
    private offsetSeconds = 3600;
    private subscriptions = new Array<Subscription>();

    constructor(
        private injector: Injector,
        private router: Router,
        private slimLoadingBarService: SlimLoadingBarService,
        private socketService: SocketService
    ) {}

    public intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        this.slimLoadingBarService.start();
        const token = localStorage.getItem(global.tokenName);

        if (request.url.startsWith(environment.baseUrl)) {
            request = request.clone({
                setHeaders: {
                    Authorization: token != null ? token : '',
                    'Content-Type': 'application/json'
                }
            });
        }

        return next.handle(request).do(
            (event: HttpEvent<any>) => {
                if (event instanceof HttpResponse) {
                    this.slimLoadingBarService.complete();
                    if (!request.url.includes('auth-tokens')) { // my api endpoint to avoid to trigger the interceptor when I refresh the token.
                        try {
                            const expirationLeft = this.jwtHelper.getTokenExpirationDate(token).getTime() - Date.now();
                            if (expirationLeft > 0 ) {
                                if (expirationLeft < (this.offsetSeconds * 1000) && !this.isUpdating) {
                                    this.updateAuthToken();
                                }
                            }
                        } catch (e) {}
                    }
                }
            },
            (error: any) => {
                this.slimLoadingBarService.complete();
                if (error instanceof HttpErrorResponse) {
                    if (error.status === 401) {
                        localStorage.clear();
                        this.socketService.close();
                        for (const sub of this.subscriptions) {
                            sub.unsubscribe();
                        }
                        this.router.navigateByUrl('/sign-in');
                    }
                }
            }
        );
    }

     /**
     * Updates the token if it will expire and the current user is navigating.
     */
    private updateAuthToken(): void {
        this.isUpdating = true;
        const authTokenRepository = this.injector.get(AuthTokenRepository);
        this.subscriptions.push(authTokenRepository.getAuthTokenUpdate().subscribe(
            (authToken: AuthToken) => {
                localStorage.setItem(global.tokenName, authToken.value);
                this.isUpdating = false;
            }
        ));
    }
}

See #18224

@rsaenen Thank you. Can you post your code for AuthTokenRepository? Specifically what does this line do const authTokenRepository = this.injector.get(AuthTokenRepository);?

Thanks again

@n0490b It just gets the AuthTokenRepository class, which is then used here: authTokenRepository.getAuthTokenUpdate()

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you have not received a response for our team (apologies for the delay) and this is still a blocker, please reply with additional information or just a ping. Thank you for your contribution! 🙇‍♂️

Was this page helpful?
0 / 5 - 0 ratings