Home > Software engineering >  Intercept Http requests to add JWT token and handle token refresh on 401 error, infinite loop of req
Intercept Http requests to add JWT token and handle token refresh on 401 error, infinite loop of req

Time:12-26

I have written the below interceptor which is working mostly as expected, apart from once my refresh token has expired, it gets stuck in a loop or re-requesting an updated access token with the expired refresh token and I can't figure out why?

My interceptor to Http requests looks like this


@Injectable()
export class AuthInterceptor implements HttpInterceptor {
    constructor(private inject: Injector){}   
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        let userService = this.inject.get(UserService)
        let authReq = request;
        authReq = this.AddTokenHeader(request, userService.getToken())
        return next.handle(authReq).pipe(
            catchError(errordata => {
                if(errordata.status === 401){
                    //401 status error, the access token needs refreshing.
                    return this.handleRefreshToken(request, next)
                }
            return throwError(() => errordata)
            })
        )
    } 

    AddTokenHeader(request: HttpRequest<any>, token: any){
        return request.clone({headers: request.headers.set('Authorization', 'Bearer ' token)})
    }

    handleRefreshToken(request: HttpRequest<any>, next: HttpHandler){
        let userService = this.inject.get(UserService)
        return userService.GenerateRefreshToken().pipe(
            switchMap((data:any) => {
                userService.updateAccessToken(data)
                return next.handle(this.AddTokenHeader(request, localStorage.getItem('accessToken')))
            }),
            catchError(errordata => {
                userService.logout()
                return throwError(() => errordata)
            })
        )
    }
}

And the UserService contains this among other functions, but I think this is the only one really relevant.

public GenerateRefreshToken(){
        return this.http.post(this.djangoPath '/api/token/refresh/', JSON.stringify({"refresh": localStorage.getItem('refreshToken')}), this.httpOptions) 
    }

I thought the catchError in the handleRefreshToken function would deal with the refresh token being expired and then result to logging out the user to force religion to generate a new refresh token, but clearly I am wrong. I am just getting repeated 401 responses from the refresh call as the token is expired. It works fine while the refresh token is valid.

Can anyone shed any light on what I am doing wrong? The backend is Django/DRF/SimpleJWT.

Finally, Merry Christmas to anybody who chooses to celebrate it.

CodePudding user response:

(You didn't mention what updateAccessToken method does, but I believe it's saving the token to the localStorage)

I believe the problem is that - userService.GenerateRefreshToken() method is also intercepted by this interceptor, so any time you get to catchError you call this function which goes into this interceptor again and calls this function - and here is the loop...

what you can do is exclude this route from being intercepted - wrap your code with this condition:

if(req.url.includes('/api/token/refresh/')) {
   // only for this route skip interceptor logic
   return next();
}

good luck :)

  • Related