Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular5 HttpInterceptor depending on the result of an Observable

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 }));
    }
}
like image 905
leonixyz Avatar asked Mar 13 '18 12:03

leonixyz


People also ask

What is the use of HttpInterceptor?

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.

Can we have multiple interceptors in angular?

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.

What is Auth interceptor in angular?

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 ).


1 Answers

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 }));
            }
        );
    }
}
like image 77
leonixyz Avatar answered Sep 28 '22 06:09

leonixyz