Add http header to loadChildren http request

670 views
Skip to first unread message

olp455...@gmail.com

unread,
Sep 19, 2017, 12:32:10 AM9/19/17
to Angular and AngularJS discussion
Hi,
I'm trying to build an application that has the following requirements:
  • Cannot use cookies, so we're using a JWT token for authentication
  • Source files must be separated by module, with all but the login module source files requiring authentication at the server
So, we're using webpack for the build and creating chunk files, and using the loadChildren feature in Angular for lazy loading the modules.

Our problem is that we cannot find a way to send our JWT token to the server via a HTTP header when Angular loads the loadChildren modules.  I don't see anyway to extend/configure the http request to add headers (or alter in any way) the http request that retrieves and loads the loadChildren source files, similar to the way that you can extend the Angular Http class to modify options, headers, etc.

Is there anyway for us to send a 'Authorization' header with the request Angular internally makes to lazy load the loadChildren files?

Thanks,
Brian

Sander Elias

unread,
Sep 19, 2017, 12:48:27 AM9/19/17
to Angular and AngularJS discussion
Hi Brian,

There are multiple ways to solve this problem. In most apps, I create my own http service(s), that takes care of all the "special requirements" for that app. (of course, I use the httpClient in there). I inject this in the module that is bootstrapped. That way you can just inject it where you need it. I. Larger apps even have more as one. For example, one for a special 3rth party service, and one for the private part of my own api's 

Regards
Sander

olp455...@gmail.com

unread,
Sep 19, 2017, 11:21:48 AM9/19/17
to Angular and AngularJS discussion
Hi Sander,
Thank you so much for the response!

So, I think I tried that, but I might be misunderstanding.  I am injecting my header in all AJAX requests by my application to our REST backend, I did this by creating my own AuthorizationHttpClient, that extends the Http class provided by @angular/http.  Then in my root module, in my providers definition, I replace the Http class with my AuthorizationHttpClient via a factory. So, that snippet looks like:

{provide: Http,
useFactory: httpFactory,
deps: [XHRBackend, RequestOptions, SessionService]
}


My AuthorizationHttpClient then injects my Authorization header with my JWT token, and that works great, all requests to my backend REST API have the token included. However, Angular doesn't seem to use its Http class (and so therefore doesn't use my AuthorizationHttpClient replacement class) when performing the loadChildren request to pull the chunked files, I've debugged it down to a very low level call in the Module loader that uses a System.import().

Am I understanding your suggestion properly?

Thank you!
Brian

Sander Elias

unread,
Sep 19, 2017, 12:57:23 PM9/19/17
to Angular and AngularJS discussion
Hi Brian,

That's not How I do it. When I'm back in tomorrow, I will clean up one of my actual services and post it here. I leave the Original http service as it is, and I provide things like Phttp(Where the P stand for private), and also I have some like someRemoteAPiHttp. 

Regards
Sander

olp455...@gmail.com

unread,
Sep 19, 2017, 1:00:04 PM9/19/17
to Angular and AngularJS discussion
That would be great. 

Thanks Sander!

Zlatko Đurić

unread,
Sep 21, 2017, 3:11:26 AM9/21/17
to Angular and AngularJS discussion
Hi Brian,

I think overriding Http or HttpClient won't help with this - Angular uses ResourceLoader to load templates etc. You would need to override that and provide your own implementation. Check this ticket as a starting point: https://github.com/angular/angular/issues/13286

Zlatko

Sander Elias

unread,
Sep 21, 2017, 3:54:41 AM9/21/17
to Angular and AngularJS discussion
Hi Brian,

This sample is based on http, but you can do something similar for httpClient. HttpClient even has the concept of interceptors that might even simplify this.
here we go:
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import {
Headers,
Http,
Response,
RequestOptions,
Request,
BaseRequestOptions,
RequestMethod,
RequestOptionsArgs,

} from '@angular/http';


@Injectable()
export class Phttp {
private token: string;

constructor(private http: Http) {
}

get(url: string, options?: RequestOptionsArgs): Observable<Response> {
options = this._myDefaultOptions(options);
return this.http.get(url, options)

}

private _header(OrgHeaders) {
if ((!this.token) ) {
this.token = getMyTokenFromSomewhere();
}
if (!this.token) {
throw Error('no token found for pHttp')
}
return new Headers({
authorization: this.token,
...OrgHeaders
})
}

private _myDefaultOptions(options?: RequestOptionsArgs) {
if (!options) {
options = new RequestOptions();
}
options.headers = this._header(options.headers)
return options;
}



post(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
options = this._myDefaultOptions(options);
return this.http.post(url, body, options)

}
put(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
options = this._myDefaultOptions(options);
return this.http.put(url, body , options)

}
delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
options = this._myDefaultOptions(options);
return this.http.delete(url, options)

}
}

Hope this is of some use to you.

Regards
Sander



olp455...@gmail.com

unread,
Sep 27, 2017, 1:14:46 PM9/27/17
to Angular and AngularJS discussion
Thank you very much for sharing Sander.  I used this exact technique to create my own http extension for applying the Authorization header to all http requests made from the application to our backend, and it works great. However, the problem is that Angular does not use this object (or the core http or httpclient) for making the http request to get the lazy loaded bundles, it uses System.import, which I would image uses the xmlhttprequest functions, although I wasn't able to debug it down to that level.  So this does work for calls made from the application, just not for the internal Angular call I need to intervene on.

Thanks,
Brian

Lucas Lacroix

unread,
Sep 27, 2017, 1:18:38 PM9/27/17
to Angular and AngularJS discussion

It seems odd that you require authorization in order to access publicly accessible assets. You would run into the same issue using a script tag in your HTML.

Can you not remove the header requirement for assets?


--
You received this message because you are subscribed to the Google Groups "Angular and AngularJS discussion" group.
To unsubscribe from this group and stop receiving emails from it, send an email to angular+u...@googlegroups.com.
To post to this group, send email to ang...@googlegroups.com.
Visit this group at https://groups.google.com/group/angular.
For more options, visit https://groups.google.com/d/optout.
--
Lucas Lacroix
Computer Scientist
Advanced Technology Division, MEDITECH

olp455...@gmail.com

unread,
Sep 27, 2017, 1:22:47 PM9/27/17
to Angular and AngularJS discussion
Thanks Zlatko, I think you might be on to what I need to do.  When I was debugging looking for the actual http mechanism being used, I did come across the resource loader. I didn't know you could override with a custom one, that might do the trick.

Brian

olp455...@gmail.com

unread,
Sep 27, 2017, 1:25:18 PM9/27/17
to Angular and AngularJS discussion
Hi Lucas,
Thanks for the response.   Yeah, our current requirement is that the source is not considered public, so we'd have to authenticate for retrieval.  Removing that requirement would make this simple, but that part is out of my control.

Brian

Lucas Lacroix

unread,
Sep 27, 2017, 1:27:38 PM9/27/17
to Angular and AngularJS discussion
How are users accessing the application in the first place? There is HTML and other assets needed in order to get to the point where Angular is running and able to import components.

Why not use the typical WebSession (ie. cookie) based authentication usually used in this situations? 

Sander Elias

unread,
Sep 27, 2017, 2:11:18 PM9/27/17
to Angular and AngularJS discussion
Brian,

Ah, now I see the problem more clear. If you are getting the modules from the root endpoint, adding JSON tokens on your own might be a tad hard. Have you considered putting the token in a secure session cookie? Not the most elegant solution, but probably the browser will add that to all requests to your server. 

Regards
Sander

olp455...@gmail.com

unread,
Sep 27, 2017, 2:45:59 PM9/27/17
to Angular and AngularJS discussion
Hi Sander, 
Yeah, unfortunately another one of our requirements is no cookies allowed, but yes, that would make this simple as well.

Brian

olp455...@gmail.com

unread,
Sep 27, 2017, 2:51:57 PM9/27/17
to Angular and AngularJS discussion
The assets for login page only are allowed to be public per our requirements.  So, the root module is all public, but then once they authenticate, I'm using loadChildren to lazy load the secure module.

Yeah, a cookie would work but we've been told we are not allowed to per some legal concerns.


Brian

Sander Elias

unread,
Sep 28, 2017, 1:14:26 AM9/28/17
to Angular and AngularJS discussion
Hi Brian,

There are (very stupid!) laws that prevent cookies. But if you look into the detail, that law is about 3rth party cookies. Not about cookies you use only the app itself. I'm not a lawyer, but I would ask about it. I think it is for now the only way, aside from monkey patching angular itself.  
It is not systemJS that does the loading of the modules, but currently webpack. (now I remember I had this discussion before ;) ) I will do a fresh round of looking into this, as it is a very valid use-case!

Regards
Sander

olp455...@gmail.com

unread,
Sep 28, 2017, 12:14:15 PM9/28/17
to Angular and AngularJS discussion
Hi Sander,
Yeah, I think with the research I've done as well as this thread, we might be able get that requirement changed.

Thanks Sander, and everyone, for your input!

Brian
Reply all
Reply to author
Forward
0 new messages