Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular 6 - Auth token interceptor not adding headers

Using Angular 6, I have tried many different approaches over the last two days, with the latest riffing off of this post: https://stackoverflow.com/a/47401544. However, the header is still not being set on requests.

import {Inject, Injectable} from '@angular/core';
import {
  HttpEvent,
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
  HttpErrorResponse,
} from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

@Injectable()
export class AuthTokenInterceptor implements HttpInterceptor {
  constructor() {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).do((event: HttpEvent<any>) => {
      if (localStorage.getItem('id_token') != null) {
        // Clone the request to add the new header.
        const request = req.clone({
          setHeaders: {
            'Content-Type' : 'application/json; charset=utf-8',
            'Accept'       : 'application/json',
            'Authorization': `Bearer ${localStorage.getItem('id_token')}`
          }
        });
        return next.handle(request);
      }
    }, (err: any) => {
      if (err instanceof HttpErrorResponse) {
        if (err.status === 401) {
          console.log('redirect auth interceptor')
          // do a redirect
        }
      }
    });
  }
}

If I log out request, the request.headers.lazyUpdate array is being updated with 3 items, but I don't see the Authorization header in the request it's intercepting.

request.headers.lazyUpdate:

{name: "Content-Type", value: "application/json; charset=utf-8", op: "s"}
{name: "Accept", value: "application/json", op: "s"}
{name: "Authorization", value: "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2Mzh9.tLTmPK46NhXSuqoCfZKgZcrQWzlNqLMI71-G0iy3bi8", op: "s"}

(request.headers.headers is empty---could this be the problem?)

app.module.ts:

providers: [
    {provide: HTTP_INTERCEPTORS, useClass: AuthTokenInterceptor, multi: true},
  ],

What leads me to think it's an interceptor issue is that if I manually add the headers to the request, I don't get a 401 and the request returns the proper data and a 200:

return this.http.get(environment.API_URL + 'list/supervise/' + encodeURIComponent(id),
      {headers: new HttpHeaders().set('Authorization', `Bearer ${localStorage.getItem('id_token')}`)}).pipe(
        map((res: any) => res.data)
    );

Is there anything I may be overlooking? Thanks.

EDIT:

As I mention in a comment below, I was returning next.handle twice. This is the solution I ended up going with:

import {Injectable} from '@angular/core';
import {
  HttpEvent,
  HttpInterceptor,
  HttpHandler,
  HttpRequest
} from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class AuthTokenInterceptor implements HttpInterceptor {
  constructor() {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const token = localStorage.getItem('id_token');

    req = req.clone({
      setHeaders: {
        'Authorization': `Bearer ${token}`
      },
    });

    return next.handle(req);
  }
}
like image 867
kriskanya Avatar asked Jul 20 '18 17:07

kriskanya


3 Answers

Full solution I went with:

import {Injectable} from '@angular/core';
import {
  HttpEvent,
  HttpInterceptor,
  HttpHandler,
  HttpRequest
} from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class AuthTokenInterceptor implements HttpInterceptor {
  constructor() {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const token = localStorage.getItem('id_token');

    req = req.clone({
      setHeaders: {
        'Authorization': `Bearer ${token}`
      },
    });

    return next.handle(req);
  }
}
like image 149
kriskanya Avatar answered Oct 24 '22 15:10

kriskanya


You could try a simpler version of it.(just like your reference link does)

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const jwt = localStorage.getItem('id_token');
    if (!!jwt) {
     req = req.clone({
       setHeaders: {
         Authorization: `Bearer ${jwt}`
       }
     });
   }
   return next.handle(req);
 }

You don't have to handle the error here
since the point of intercepter here(in your context) is to clone(that means whenever we took request, we clone it, then do whatever we want and send it away).
We could add more headers more data
And it will be sent away, then eventually coming back with return from Api
And leave the handle problem to the service that call the httpRequest(eg: then, catch, pipe,...).

Again, you declared this in app.module.ts which mean all of the requestto api in your app will be intercept, and what if I want to handle a specific request with the error message Nothing here?, and if you do some complicated logic, it could affect all request.

And about your code above, I haven't try it, but I think their could be something wrong happened when you nested like that or so, you should put the break point their and tried to debug what happened.

like image 26
lupa Avatar answered Oct 24 '22 15:10

lupa


So the first issue i see here is that u dont return if there is no value in localStorage. i would structure the interceptor like this:

export class AuthInterceptor implements HttpInterceptor {

    private APIToken = null;
    private defaultApplicationHeaders = {
        'Content-Type': 'application/json'
    }

    buildRequestHeaders():HttpHeaders {

        let headers = this.defaultApplicationHeaders;

        // set API-Token if available
        if(this.APIToken !== null) {
            let authHeaderTpl = `Bearer ${this.APIToken}`;
            headers['Authorization'] = authHeaderTpl
        }

        return new HttpHeaders(headers);
    }

    constructor() {
        this.APIToken = localStorage.getItem('id_token')
    }

    intercept(req: HttpRequest<any>, next: HttpHandler) {
        const headers = this.buildRequestHeaders();
        const authReq = req.clone({ headers });

        return next.handle(authReq);
    }
}
like image 26
enno.void Avatar answered Oct 24 '22 13:10

enno.void