Angular2-jwt: v1.0 branch, do not send token for some calls

Created on 16 Nov 2017  ·  15Comments  ·  Source: auth0/angular2-jwt

Hi,

With the v1 branch, this library provides an HttpInterceptor which automatically attaches the JWT to all HttpClient request. But what if I want to send the JWT only for some routes, and not others ? Is there a way to do this ?

Regards.

stale

Most helpful comment

My solution (relevant code):

Auth Service:

signIn(email, password) {
    ...

    let headers = new HttpHeaders();
    headers = headers.append('extra', 'noToken');

    return this.http.post('/auth/login', data, {headers: headers})
      .map((response: any) => {
          ...
      })
      .catch(...);
  }

Interceptor:

export class HeadersInterceptor implements HttpInterceptor {
  constructor() {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    let headers = req.headers
      .set('Content-Type', 'application/json');

    if (headers.get('extra') === 'noToken') {
      headers = headers.delete('Authorization').delete('extra');
    }

    const authReq = req.clone({headers: headers});

    return next.handle(authReq);
  }
}

All 15 comments

I'm looking for the same feature.

We use the same HttpClient to login and access protected resources. I don't want to try and send the JWT with a login request.

Maybe, it would be nice if there would be a way to specify whitelisted urls instead of just domains?

@sylvainlap I've implemented something that might work: https://github.com/jgornick/angular2-jwt/commit/d8ac54557df446ea0f55f44f2a24bd2796f4a3b7

Certainly overriding the whitelist domains to include paths, but in a separate interface.

Thoughts?

sounds great !

Another implementation here might be to use a function for whitelisted domains. This provides more flexibility to the library consumer for implementing if the request is whitelisted.

I've updated the implementation to use whitelistPredicate and removed whitelistDomains: https://github.com/jgornick/angular2-jwt/tree/v1.0

I think it would be more practical to have a way to suppress the token on each individual HTTP call. Otherwise one needs centrally managed knowledge of all whitelisted URIs. Also one might want to call one URI with or without the token, depending on the situation.

@achimha Can you provide an example of this implementation?

I'm not entirely sure how to do it best. I have created my own implementation of JWT because of this. What I do is add a "magic" header through the options of each HTTP call and in my interceptor I check if the header is present in case it is, I remove it and skip the JWT header.

Another idea would be to inject two versions of HttpClient, one with the JWT interceptor and one without but I couldn't get this to work so went for the header.

I can't believe they didn't think about this...
This "feature" is mandatory!

The documentation says:

Any requests sent using Angular's HttpClient will automatically have a token attached as an Authorization header.

It's obvious and with a very high probability that we don't want that authorization token in every request...

To be honest, with HttpClient and its HttpInterceptor, the JWT use case is so trivial that I don't see a need for this library.

My solution (relevant code):

Auth Service:

signIn(email, password) {
    ...

    let headers = new HttpHeaders();
    headers = headers.append('extra', 'noToken');

    return this.http.post('/auth/login', data, {headers: headers})
      .map((response: any) => {
          ...
      })
      .catch(...);
  }

Interceptor:

export class HeadersInterceptor implements HttpInterceptor {
  constructor() {
  }

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    let headers = req.headers
      .set('Content-Type', 'application/json');

    if (headers.get('extra') === 'noToken') {
      headers = headers.delete('Authorization').delete('extra');
    }

    const authReq = req.clone({headers: headers});

    return next.handle(authReq);
  }
}

@achimha I use this library for its .decodeToken. It's pretty shameful to have removed the distinction of having both an Http and authHttp. I might just follow the Angular guide on HttpInterceptor and implement by own jwt, but the I still need to import this library to decode my tokens anyway.

I use https://github.com/auth0/jwt-decode which provides the decoding part of this library. The rest I do myself with a lot less code than before:

import { Injectable } from '@angular/core';
import { TokenStorage } from '../auth/auth.service';
import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { Router } from '@angular/router';

@Injectable()
export class ARHttpInterceptor implements HttpInterceptor {
    constructor(
        private router: Router
    ) {
    }

    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if (req.headers.has('x-ar-noauth')) {
            return next.handle(req.clone({ headers: req.headers.delete('x-ar-noauth')}));
        } else {
            let token = TokenStorage.getToken();
            if (token) {
                req = req.clone({ headers: req.headers.append('Authorization', 'Bearer ' + token)});
            }
            return next.handle(req).do(
                () => {},
                (err: any) => {
                    if (err instanceof HttpErrorResponse) {
                        if (err.status === 401 ||
                            (err.status === 400 && err.statusText.indexOf('token_not_provided') !== -1)
                        ) {
                            TokenStorage.clearToken();
                            /* go to login unless it was a logout command */
                            if (!/\/logout$/.test(req.url)) {
                                this.router.navigate(['/login']).then();
                            }
                        }
                    }
                });
        }
    }
}

So what I do for non-auth calls is add a header x-ar-noauth which signals to the interceptor to not add the token. If it's present, the header will be removed.

@achimha Are you using Angular 5 and the https://github.com/auth0/jwt-decode to decode?
I just tried that library and I could not get it to work. Did you have to set anything in the app.module for jwt-decode? I was getting a provider error on one of the methods in that library. I simply stayed with angular2-jwt as a decoder for now. That other lib seems dead.

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. If you have not received a response for our team (apologies for the delay) and this is still a blocker, please reply with additional information or just a ping. Thank you for your contribution! 🙇‍♂️

Was this page helpful?
0 / 5 - 0 ratings