DEV Community

seanbh
seanbh

Posted on • Originally published at Medium on

How to Add a Bearer Token to API calls when Using NgRx


Photo by Simon Hurry on Unsplash

With Angular, you don’t have to add the Bearer authorization token to the header of every API call manually. Instead you can use an HttpInterceptor , which allows you to intercept every HTTP request and modify it before passing it through to the rest of the pipeline. Let’s take a look.

Adding an HttpInterceptor

You can use the CLI to create an interceptor with the following command:

ng g interceptor auth
Enter fullscreen mode Exit fullscreen mode

This creates an auth.interceptor.ts file with a single method:

@Injectable()
export class AuthInterceptor implements HttpInterceptor {

  constructor() {}

  intercept(request: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    return next.handle(request);
  }
}
Enter fullscreen mode Exit fullscreen mode

You’re meant to modify the HTTP request as needed, and then pass it through to the next handler in the pipeline. We’ll come back to this in a moment. For now just note that it returns an Observable.

Next we need to let Angular know to plug our interceptor into the request pipeline. In app.module.ts, add this new interceptor class to the providers array:

providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
]
Enter fullscreen mode Exit fullscreen mode

Now the intercept method of AuthInterceptor will be called on every HTTP request. But it doesn’t yet do anything — let’s fix that.

Adding the User’s Bearer Token to the HTTP Request Header

We want to add an Authorization header that contains the Bearer token of the currently logged in User. If you use NgRx in your application, then there’s a good chance that token is stored in NgRx state. Since the intercept method returns an Observable, we can use the mergeMap operator to get the token from state and then modify the request to add it as an HTTP header. Change the intercept method to look like this:

intercept(req: HttpRequest<unknown>, next: HttpHandler): Observable<HttpEvent<unknown>> {
    if (this.appConfig.apiHost && 
        req.url.startsWith(this.appConfig.apiHost)) {
      return this.store.select(userFeature.selectCurrentUser).pipe(
        first(),
        mergeMap((currentUser) => {
          if (currentUser) {
            const authReq = req.clone({
              setHeaders: {
                Authorization: `Bearer ${currentUser.authToken}`
              },
            });
            return next.handle(authReq);
          }
          return next.handle(req);
        })
      );
    }
    return next.handle(req);
  }
Enter fullscreen mode Exit fullscreen mode

Let’s break this down.

First, we want to make sure that this request is going to our API host. Otherwise, not only is the token not needed, but we don’t want to send the Bearer token anywhere other than our API. So if the request URL does not start with our API host, we just pass it through unchanged.

Next we select the current User from state with this.store.select. Note the return keyword. Recall that we need to return an Observable, so we’ll project the Observable returned by this.store.select into the Observable that this method returns.

We use the first operator because we only need the first value.

Next we use the mergeMap operator to project (and flatten) the Observable that gives us currentUser, into the Observable returned by next.handle(req).

Inside mergeMap, if we don’t have the User in state for some reason, we just pass the request through unchanged. Otherwise, we clone the request and add the Authorization header to it. Then we pass the cloned request on to the next handler in the pipeline.

Now every call to our API will have the User’s bearer token added to the HTTP Authorization header.

In a future post, we’ll look at how we can unit test this interceptor.

Bibliography

Top comments (0)