Angular 2 (Final) Extending Http Provider

Adding JWT `authorization` header to every http request

Posted by Adones Pitogo on Oct 31, 2016

Been learning Angular 2 for a week now. Though most of the Angular 1.x concepts are familiar in Angular 2, they are now implemented differently. One hendous problem I encountered was creating a token-based authentication system for my personal project. The api is an Express application that uses express-jwt plugin. Thus, I had to add authorization header to every http requests containing the authentication token.

In Angular 1.x, we use $http interceptors to hijack every http requests. But Angular 2 doensn’t provide the same functionality. The best solution I can think of is to extend the Http class and make a custom Http provider which automatically adds the authentication token to every http request.

The most frustrating problem I had during my attempt to extend the Http class was encountering an error No provider for ConnectionBackend!. Most of the solutions provided in Stack Overflow are for the pre-release versions of Angular 2, which have changed after the final release. I’m on Angular version 2.1.1 at the time of writing this article. After some reading, I found out that Angular 2 has multiple providers for ConnectionBackend namely: JSONPBackend_ and XHRBackend. Let’s use the XHRBackend from @angular/http module.


Create Custom Http Class

First, lets create our custom http provider class.

http.service.ts

import {Injectable} from '@angular/core';
import {Http, XHRBackend, RequestOptions, Request, RequestOptionsArgs, Response, Headers} from '@angular/http';
import {Observable} from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';

@Injectable()
export class HttpService extends Http {

  constructor (backend: XHRBackend, options: RequestOptions) {
    let token = localStorage.getItem('auth_token'); // your custom token getter function here
    options.headers.set('Authorization', `Bearer ${token}`);
    super(backend, options);
  }

  request(url: string|Request, options?: RequestOptionsArgs): Observable<Response> {
    let token = localStorage.getItem('auth_token');
    if (typeof url === 'string') { // meaning we have to add the token to the options, not in url
      if (!options) {
        // let's make option object
        options = {headers: new Headers()};
      }
      options.headers.set('Authorization', `Bearer ${token}`);
    } else {
    // we have to add the token to the url object
      url.headers.set('Authorization', `Bearer ${token}`);
    }
    return super.request(url, options).catch(this.catchAuthError(this));
  }

  private catchAuthError (self: HttpService) {
    // we have to pass HttpService's own instance here as `self`
    return (res: Response) => {
      console.log(res);
      if (res.status === 401 || res.status === 403) {
        // if not authenticated
        console.log(res);
      }
      return Observable.throw(res);
    };
  }
}

Configure the Custom Http Class

Now, we need to configure our main module to provide the XHRBackend to our custom http class. In your main module declaration, add the following to the providers array:

app.module.ts

import { HttpModule, RequestOptions, XHRBackend } from '@angular/http';
import { HttpService } from './services/http.service';
...
@NgModule({
  imports: [..],
  providers: [
    {
      provide: HttpService,
      useFactory: (backend: XHRBackend, options: RequestOptions) => {
        return new HttpService(backend, options);
      },
      deps: [XHRBackend, RequestOptions]
    }
  ],
  bootstrap: [ AppComponent ]
})

After that, you can now use your custom http provider in your services. For example:

user.service.ts

import { Injectable }     from '@angular/core';
import {HttpService} from './http.service';

@Injectable()
class UserService {
  constructor (private http: HttpService) {}

  // token will added automatically to get request header
  getUser (id: number) {
    return this.http.get(`/users/${id}`).map((res) => {
      return res.json();
    } );
  }
}

That’s all there is to create your custom http provider. Thanks for reading.

Share: Email Twitter Facebook Google LinkedIn Reddit StumbleUpon Tumblr Buffer Digg