angular2-jwt: Authorization header not being sent - Angular 5

I am having this same issue consistently in a prod environment using Angular 5 but It works completely fine locally! I installed using this command: npm install @auth0/angular-jwt

For a tl;dr - I was previously using Angular 4.4.6 with angular2-jwt, but now that http is deprecated, I am using HttpClient with this newer version of angular-jwt.

Here is what I have done: My app.module.ts looks as follows (showing both the inline function and a custom factory syntax that I tried)

// app.module.ts
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { JwtModule, JWT_OPTIONS } from '@auth0/angular-jwt';
import { TokenService } from './_services/token.service';

export function jwtOptionsFactory(tokenService) {
  return {
    tokenGetter: () => {
      return tokenService.get();
    },
    whitelistedDomains: ['budgetivity.com', 'budgetivity.local']
  };
}

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
	...
    HttpClientModule,
    JwtModule.forRoot({
      config: {
        tokenGetter: () => {
          return sessionStorage.getItem('token');
        },
        whitelistedDomains: ['budgetivity.com', 'budgetivity.local']
      }
      // jwtOptionsProvider: {
      //   provide: JWT_OPTIONS,
      //   useFactory: jwtOptionsFactory,
      //   deps: [TokenService]
      // }
    }),

I am using full IIS locally with my host file pointing to 127.0.0.1 for budgetivity.local

When I run locally, I am building for dev and I use the ng-build command and my environment.ts looks as follows:

export const environment = {
	...
  baseUrl: 'http://budgetivity.local',
	...
};

When I build for prod I use ng build --env=prod and my environment.prod.ts looks as follows:

export const environment = {
	...
  baseUrl: 'https://www.budgetivity.com',
	...
};

But - when running a ng-build --prod command I get an error if I am using the function syntax instead of the custom service syntax. “Error encountered resolving symbol values statically. Function calls are not supported.” So when using the ng-build --prod command I must switch the code to only use the custom service syntax.

When running locally, my requests are sucessfully sent to my local API and have an appropriate Authorization: Bearer XXXX (token) When built for and deployed to Prod, the requests do not have an Authorization header at all.

I have even built for dev but used the Prod baseUrl - when that is deployed to Prod that also does not send the Authorization header in any of the requests.

For sake of completeness here is my tokenService and a method that calls my API:

// token.service.ts
import { Injectable } from '@angular/core';

@Injectable()
export class TokenService {

  public get(): string {
    return sessionStorage.getItem('token');
  }

  public set(token: string): void {
    sessionStorage.setItem('token', token);
  }

  public deleteToken(): void {
    sessionStorage.removeItem('token');
  }
}
// session.service.ts
import { environment } from '../../environments/environment';
...
  public isSessionValid(): Observable<any> {
    return this.http.get(`${environment.baseUrl}/api/v1/sessions`)
      .catch((error: Response) => {
        return Observable.throw(error);
      });
  }

Here is what my local call looks like: image

and here is what it looks like on Prod: image

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 19 (1 by maintainers)

Most upvoted comments

Hey! I had the same issue where token wasn’t being passed to the server on production. But my issue got resolved by updating the whitelistedDomains array.

JwtModule.forRoot({
      config: {
        tokenGetter: tokenGetter,
        whitelistedDomains: ['localhost:8000','prod-1.app.io','api.prod-2.app.io'],
        authScheme: 'JWT '
      }
    })

Solutions that worked for me:

  1. Use interceptor https://stackoverflow.com/a/45363296
  2. Use HttpClient module instead of Http

Hey! I had the same issue where token wasn’t being passed to the server on production. But my issue got resolved by updating the whitelistedDomains array.

JwtModule.forRoot({
      config: {
        tokenGetter: tokenGetter,
        whitelistedDomains: ['localhost:8000','prod-1.app.io','api.prod-2.app.io'],
        authScheme: 'JWT '
      }
    })

Thaaanks @hemangsk whitelistedDomains should be without “http://” or “https://”, this was my issue

Just configure your app module by this way:

...
import {JwtInterceptor, JwtModule} from '@auth0/angular-jwt';
...

@NgModule({
  imports: [
    ...
    JwtModule.forRoot({
      config: {
        tokenGetter: () => localStorage.getItem('varName'),
        whitelistedDomains: ['foo.bar']
      }
    })
  ],
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: JwtInterceptor, multi: true}
    ...
  ],
  ...
})

For what it’s worth, I ended up ditching this library altogether. For determining if a user is still logged in instead of decoding the token on the front end I send a request to my API to a SessionsController that is authorized and simply returns Ok if the authorization attribute logic passes - determines that the token exists in the DB, hasn’t expired and hasn’t been administratively deactivated. This is much safer and gives the server control of determining if the session is actually valid or not. If it’s not valid it returns a 401 and my guard informs the user and signs them out.

// secure.guard.ts
...
@Injectable()
export class SecureGuard implements CanActivate {

  constructor(private router: Router,
              private alertService: AlertService,
              private sessionService: SessionService) { }

  public canActivate() {
    return this.serverSessionIsValid();
  }

  public serverSessionIsValid(): Observable<boolean> {
    return Observable.create((observer) => {
      this.sessionService.isSessionValid().subscribe(
        () => {
          observer.next(true);
          observer.complete();
        },
        () => {
          observer.next(false);
          observer.complete();
          this.sessionService.clearSession();
          this.router.navigate(['/sign-in']);
          this.alertService.alert(AlertType.error, 'Your session has expired, you will need to log in.');
        });
    });
  }
...

For adding the authorization header, I just add it to the necessary calls like so:

// session.service.ts
...
  public get authHeader(): string {
    return `Bearer ${sessionStorage.getItem('token')}`;
  }
...
  public isSessionValid(): Observable<any> {
    return this.http.get(`${environment.baseUrl}/api/v1/sessions`, {
      headers: new HttpHeaders().set('Authorization', this.authHeader)
    })
    .catch((error: Response) => {
      return Observable.throw(error);
    });
  }
...