I am trying to implement using Angular5 an HttpInterceptor
to inject an Authorization header in all HTTP requests.
I rely on a third party library (ADAL, here called AuthService
) that exposes a acquireToken()
method to get the token to be used for Bearer authorization.
The problem is that aquireToken()
returns an observable, and i have to subscribe to get the real string I need.
Therefore, my code never injects the header, i suppose because next.handle()
is executed before acquireToken()
returns any value.
How can i ensure that the next handler is called only after the token has been retrieved?
import { Injectable, Injector } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import {AuthService} from 'mylibrary';
@Injectable()
export class MyInterceptor implements HttpInterceptor {
constructor(private auth: AuthService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
let headers = req.headers || new HttpHeaders();
this.auth.acquireToken(req.url)
.subscribe((token: string) => {
headers = headers.append('Authorization', 'Bearer ' + token);
});
return next.handle(req.clone({ headers: headers }));
}
}
Angular interceptors manipulate the headers as they provide features such as authentication and authorization. The angular HTTP interceptors are used to protect the application against XSRF. Interceptor can even convert the format of an API that we receive.
After providing HTTP_INTERCEPTORS we need to inform the class we are going to implement our interceptor into by using useClass. Setting multi to true, makes sure that you can have multiple interceptors in your project.
Angular JWT Interceptor The JWT Interceptor intercepts HTTP requests from the application to add a JWT auth token to the HTTP Authorization header if the user is logged in and the request is to the Angular app's API URL ( environment. apiUrl ).
This code will do the job, the trick is using mergeMap
import { Injectable, Injector } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { AdalService } from './adal.service';
import 'rxjs/add/operator/mergeMap';
@Injectable()
export class AdalInterceptor implements HttpInterceptor {
constructor(private adal: AdalService) { }
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// if the endpoint is not registered then pass
// the request as it is to the next handler
const resource = this.adal.GetResourceForEndpoint(req.url);
if (!resource) {
return next.handle(req.clone());
}
// if the endpoint is registered then acquire and inject token
let headers = req.headers || new HttpHeaders();
return this.adal.acquireToken(resource)
.mergeMap((token: string) => {
// if the user is not authenticated then drop the request
if (!this.adal.userInfo.authenticated) {
throw new Error('Cannot send request to registered endpoint if the user is not authenticated.');
}
// inject the header
headers = headers.append('Authorization', 'Bearer ' + token);
return next.handle(req.clone({ headers: headers }));
}
);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With