vigamage
vigamage

Reputation: 2113

Appending Headers to HTTP requests Globally and Dynamically - Angular2

I need an Authorization header to be appended to each and every HTTP request done by my Angular2 app.

The first request would be the login request, which does not have an authorization header. Once the login in is successful, a token is returned from the server and I need that to be appended as an authorization header to each and every subsequent HTTP requests.

I am getting the the token from the server without any problem. I can log in successfully using my angular2 app. But the problem is, the token is not attached to subsequent request headers.

This is my implementation.

I have created a CustomRequestOptions class extending the BaseRequestOptions class.

@Injectable()
export class CustomRequestOptions extends BaseRequestOptions {
    constructor(private _globals: Globals) {
        super();
        this.headers.append('Content-Type', 'application/json');
    }

    addHeader(headerName: string, headerValue: string) {
       console.log("Custom req options, setting the customer header "+headerName+" , "+headerValue);
       this.headers.append(headerName, headerValue);
    }
}

I have added that to @NgModule in order for this CustomRequestOptions to be global.(to be visible across all the components)

@NgModule({
  imports:      [ BrowserModule, HttpModule, routing, FormsModule ],
  declarations: [ AppComponent, TendersComponent, TenderCategoriesComponent, TenderDetailsComponent, PageNotFoundComponent, ConvertUrlPipe ],
  providers   : [ Globals, 
        {provide: RequestOptions, useClass: CustomRequestOptions}
    ],
  bootstrap:    [ AppComponent ]
}) 

Now, in my component class, I am calling the addHeader method in CustomRequestOptions.

export class LoginComponent {

  private _token: string;
  private _returnMsg: string;

  constructor(private _usersService: UsersService, private _globals: Globals, private _customRequestOptions: CustomRequestOptions) {

  }

  onLoginFormSubmit(formData: any) {

    this._usersService.login(formData.emailAddress, formData.password).subscribe(

      returnRes => {

        this._returnMsg = returnRes.returnMsg;
        this._token = returnRes.token;

        if (this._returnMsg == "SUCCESS") {

          //sucess
          console.log("AUTH SUCCESS");
          let x = "Bearer " + this._token;
          this._customRequestOptions.addHeader("Authorization", x);

          this.getUserRoles(); //this call needs authorization header.

        }

      }

    );

  }

}

Even though I set the header using this._customRequestOptions.addHeader("Authorization", x);, the next call, which needs Authorization header in order to work properly, fails. In server side,I can see, that part is null.

What is wrong here?

Upvotes: 1

Views: 1848

Answers (1)

Tyler Jennings
Tyler Jennings

Reputation: 8911

The problem of extending BaseRequestOptions is that the constructor is only run once in the lifetime of the browser and beyond that, the changes will not propagate. And, the changes would need to be in the super call like this:

super({ 
  method: RequestMethod.Get,
  headers: new Headers({
    'Content-Type': 'application/json',
    'X-Some-Header': 'some-content'
  });
});

Manipulation outside of super of the headers property does not work. The other option in extending the BaseRequestOptions is to do it once in your module:

class DefaultRequestOptions extends BaseRequestOptions{
    headers:Headers = new Headers({
        'Content-Type': 'poop'
    });
}
....
providers: [{provide: RequestOptions, useClass: DefaultRequestOptions}],

There used to be a way in earlier versions of Angular2 where you could access the _defaultOptions object on http, but it is now protected and inaccessible. It looked like this: this.http._defaultOptions.headers.set('Authorization', 'token');

TLDR;

If you need to change headers during the lifetime of your application then I'd suggest looking at something like https://github.com/auth0/angular2-jwt or writing your own wrapper to the http library(similar to how angular2-jwt does it). I've written my own fork to handle my use cases before where I can say 'if something exists, then do x'. If you decide to write you're own, it's not that difficult, you can look at https://github.com/auth0/angular2-jwt/blob/master/angular2-jwt.ts#L94 for inspiration. This would replace the normal http library in @angular/http.

Sorry, that is probably not the solution you were looking for, but this is what I've learned trying to tackle the same challenge. Hope it sheds some light on the problem with your code and potential solutions.

Upvotes: 1

Related Questions