Angular: Adding bearer token in interceptor

Viewed 325

I'm working with Angular + AWS Cognito

I was able to login and need to add cognito bearer token

@Injectable({
providedIn: 'root',
})
export class InterceptorService implements HttpInterceptor {
constructor(public loaderService: LoaderService, private router: Router) { }

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.getToken().pipe(
        mergeMap((token) => {
            request = request.clone(
                {
                    setHeaders: { Authorization: `Bearer ${token}` }
                });

            return next.handle(request);
        })
    );
}

getToken() {
    return from(
        new Promise((resolve, reject) => {
            Auth.currentSession().then((session) => {
                if (!session.isValid()) {
                    resolve(null);
                } else {
                    resolve(session.getIdToken().getJwtToken());
                }
            }).catch(err => { return resolve(null) });
        })
    );
}
}

This code works fine, the problem is how to handle HttpResponse here?

I tried following code but it didn't work, the request have no Bearer token

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        return next.handle(request).pipe(
            tap(
            (event) => {
                if (event instanceof HttpResponse) {
                    if (event.status !== 200) {
                        console.log('Response', event.status);
                    }
                } else {
                    return this.getToken().pipe(
                       mergeMap((token) => {
                            request = request.clone(
                                {
                                    setHeaders: { Authorization: `Bearer ${token}` }
                                });

                            return next.handle(request);
                        })
                    );
                }
            },
            (error) => {
                 // to handle errors
            }
        )
}
3 Answers

As far as I know tap only runs, when there is no error. If you want your function to run on an error you have to use catchError() in the pipe.

tap is operator to do side effects, you can't just return observable from callback, it won't be subscribed on. also a logic where you send the original request, and retry it with token if it fails is a bit strange. I believe you should add token to every request.

intercept(...) {
  return this.sendWithToken(request).pipe(
    catchError(error => error.status === 401 ? this.sendWithToken(request) : throwError(error)) // try one more time if return code is 401 
  );
}

sendWithToken(request: ...) {
  return this.getToken().pipe(
    mergeMap(token => addToken(request)),
    mergeMap(authedRequest => next.handle(authedRequest)),
  );
}

also getToken code could be improved, becase you don't need to create promise if you already have one

getToken() {
    return from(
        Auth.currentSession().then((session) => {
            if (!session.isValid()) {
                return null;
            } else {
                return session.getIdToken().getJwtToken();
            }
        }).catch(err => null);
    );
}

I resolved this with following interceptor code:

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return this.getToken().pipe(
        mergeMap((token) => {
            request = request.clone(
                {
                    headers: request.headers.set('Authorization', `Bearer ${token}`)
                });

            return next.handle(request).pipe(
                tap(evt => {
                      // modify here
                }),
                catchError((error: any) => {
                    if (error && error.status) {
                        if (error.status == 401) {
                            this.router.navigate(['/']);
                        }
                    } else {
                        return throwError(error);
                    }
                })
            )
        })
    );
}

getToken() {
    return from(
        Auth.currentSession().then((session) => {
            if (!session.isValid()) {
                return null;
            } else {
                return session.getIdToken().getJwtToken();
            }
        }).catch(err => null)
    );
}
Related