From f7cf1cc24500f495dbd8a04dd91e1a34ae2e130b Mon Sep 17 00:00:00 2001 From: frederikprijck Date: Tue, 25 Oct 2022 10:25:58 +0200 Subject: [PATCH 1/5] Support promise based tokenGetter in JwtHelperService --- .../angular-jwt/src/lib/jwt.interceptor.ts | 77 ++++++++-------- .../src/lib/jwthelper.service.spec.ts | 88 +++++++++++++++++++ .../angular-jwt/src/lib/jwthelper.service.ts | 44 ++++++++-- src/app/services/example-http.service.spec.ts | 85 +++++++++++++++++- 4 files changed, 251 insertions(+), 43 deletions(-) create mode 100644 projects/angular-jwt/src/lib/jwthelper.service.spec.ts diff --git a/projects/angular-jwt/src/lib/jwt.interceptor.ts b/projects/angular-jwt/src/lib/jwt.interceptor.ts index 11f3fbfd..b7012424 100644 --- a/projects/angular-jwt/src/lib/jwt.interceptor.ts +++ b/projects/angular-jwt/src/lib/jwt.interceptor.ts @@ -1,17 +1,23 @@ -import { Injectable, Inject } from '@angular/core'; +import { Injectable, Inject } from "@angular/core"; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, -} from '@angular/common/http'; -import { DOCUMENT } from '@angular/common'; -import { JwtHelperService } from './jwthelper.service'; -import { JWT_OPTIONS } from './jwtoptions.token'; +} from "@angular/common/http"; +import { DOCUMENT } from "@angular/common"; +import { JwtHelperService } from "./jwthelper.service"; +import { JWT_OPTIONS } from "./jwtoptions.token"; -import { mergeMap } from 'rxjs/operators'; -import { from, Observable } from 'rxjs'; +import { map, mergeMap } from "rxjs/operators"; +import { defer, from, Observable, of } from "rxjs"; +const fromPromiseOrValue = (input: T | Promise) => { + if (input instanceof Promise) { + return defer(() => input); + } + return of(input); +}; @Injectable() export class JwtInterceptor implements HttpInterceptor { tokenGetter: ( @@ -23,7 +29,7 @@ export class JwtInterceptor implements HttpInterceptor { disallowedRoutes: Array; throwNoTokenError: boolean; skipWhenExpired: boolean; - standardPorts: string[] = ['80', '443']; + standardPorts: string[] = ["80", "443"]; constructor( @Inject(JWT_OPTIONS) config: any, @@ -31,11 +37,11 @@ export class JwtInterceptor implements HttpInterceptor { @Inject(DOCUMENT) private document: Document ) { this.tokenGetter = config.tokenGetter; - this.headerName = config.headerName || 'Authorization'; + this.headerName = config.headerName || "Authorization"; this.authScheme = - config.authScheme || config.authScheme === '' + config.authScheme || config.authScheme === "" ? config.authScheme - : 'Bearer '; + : "Bearer "; this.allowedDomains = config.allowedDomains || []; this.disallowedRoutes = config.disallowedRoutes || []; this.throwNoTokenError = config.throwNoTokenError || false; @@ -54,13 +60,13 @@ export class JwtInterceptor implements HttpInterceptor { // If not the current domain, check the allowed list const hostName = `${requestUrl.hostname}${ requestUrl.port && !this.standardPorts.includes(requestUrl.port) - ? ':' + requestUrl.port - : '' + ? ":" + requestUrl.port + : "" }`; return ( this.allowedDomains.findIndex((domain) => - typeof domain === 'string' + typeof domain === "string" ? domain === hostName : domain instanceof RegExp ? domain.test(hostName) @@ -77,7 +83,7 @@ export class JwtInterceptor implements HttpInterceptor { return ( this.disallowedRoutes.findIndex((route: string | RegExp) => { - if (typeof route === 'string') { + if (typeof route === "string") { const parsedRoute: URL = new URL( route, this.document.location.origin @@ -103,25 +109,26 @@ export class JwtInterceptor implements HttpInterceptor { next: HttpHandler ) { const authScheme = this.jwtHelper.getAuthScheme(this.authScheme, request); - let tokenIsExpired = false; if (!token && this.throwNoTokenError) { - throw new Error('Could not get token from tokenGetter function.'); + throw new Error("Could not get token from tokenGetter function."); } - if (this.skipWhenExpired) { - tokenIsExpired = token ? this.jwtHelper.isTokenExpired(token) : true; + if (token) { + return fromPromiseOrValue(this.jwtHelper._isTokenExpired(token)).pipe( + map((isExpired) => + isExpired && this.skipWhenExpired + ? request.clone() + : request.clone({ + setHeaders: { + [this.headerName]: `${authScheme}${token}`, + }, + }) + ), + mergeMap((request) => next.handle(request)) + ); } - if (token && tokenIsExpired && this.skipWhenExpired) { - request = request.clone(); - } else if (token) { - request = request.clone({ - setHeaders: { - [this.headerName]: `${authScheme}${token}`, - }, - }); - } return next.handle(request); } @@ -134,14 +141,10 @@ export class JwtInterceptor implements HttpInterceptor { } const token = this.tokenGetter(request); - if (token instanceof Promise) { - return from(token).pipe( - mergeMap((asyncToken: string | null) => { - return this.handleInterception(asyncToken, request, next); - }) - ); - } else { - return this.handleInterception(token, request, next); - } + return fromPromiseOrValue(token).pipe( + mergeMap((asyncToken: string | null) => { + return this.handleInterception(asyncToken, request, next); + }) + ); } } diff --git a/projects/angular-jwt/src/lib/jwthelper.service.spec.ts b/projects/angular-jwt/src/lib/jwthelper.service.spec.ts new file mode 100644 index 00000000..81128489 --- /dev/null +++ b/projects/angular-jwt/src/lib/jwthelper.service.spec.ts @@ -0,0 +1,88 @@ +import { TestBed } from '@angular/core/testing'; +import { + HttpClientTestingModule, +} from '@angular/common/http/testing'; +import { JwtModule, JwtHelperService } from 'angular-jwt'; + +describe('Example HttpService: with simple based tokken getter', () => { + let service: JwtHelperService; + let tokenGetter = jasmine.createSpy('tokenGetter'); + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + HttpClientTestingModule, + JwtModule.forRoot({ + config: { + tokenGetter: tokenGetter, + allowedDomains: ['example-1.com', 'example-2.com', 'example-3.com'], + }, + }), + ], + }); + service = TestBed.inject(JwtHelperService); + }); + + it('should return null when tokenGetter returns null', () => { + tokenGetter.and.returnValue(null); + + expect(service.decodeToken()).toBeNull(); + }); + + it('should throw an error when token contains less than 2 dots', () => { + tokenGetter.and.returnValue('a.b'); + + expect(() => service.decodeToken()).toThrow(); + }); + + it('should throw an error when token contains more than 2 dots', () => { + tokenGetter.and.returnValue('a.b.c.d'); + + expect(() => service.decodeToken()).toThrow(); + }); +}); + +describe('Example HttpService: with a promise based tokken getter', () => { + let service: JwtHelperService; + let tokenGetter = jasmine.createSpy('tokenGetter'); + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + HttpClientTestingModule, + JwtModule.forRoot({ + config: { + tokenGetter: tokenGetter, + allowedDomains: ['example-1.com', 'example-2.com', 'example-3.com'], + }, + }), + ], + }); + service = TestBed.inject(JwtHelperService); + }); + + it('should return null when tokenGetter returns null', async () => { + tokenGetter.and.resolveTo(null); + + await expectAsync(service.decodeToken()).toBeResolvedTo(null); + }); + + it('should throw an error when token contains less than 2 dots', async () => { + tokenGetter.and.resolveTo('a.b'); + + await expectAsync(service.decodeToken()).toBeRejected(); + }); + + it('should throw an error when token contains more than 2 dots', async () => { + tokenGetter.and.resolveTo('a.b.c.d'); + + await expectAsync(service.decodeToken()).toBeRejected(); + }); + + it('should return the token when tokenGetter returns a valid JWT', async () => { + tokenGetter.and.resolveTo('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE2NjY2ODU4NjAsImV4cCI6MTY5ODIyMTg2MCwiYXVkIjoid3d3LmV4YW1wbGUuY29tIiwic3ViIjoianJvY2tldEBleGFtcGxlLmNvbSIsIkdpdmVuTmFtZSI6IkpvaG5ueSIsIlN1cm5hbWUiOiJSb2NrZXQiLCJFbWFpbCI6Impyb2NrZXRAZXhhbXBsZS5jb20iLCJSb2xlIjpbIk1hbmFnZXIiLCJQcm9qZWN0IEFkbWluaXN0cmF0b3IiXX0.lXrRPRZ8VNUpwBsT9fLPPO0p0BotQle4siItqg4LqLQ'); + + await expectAsync(service.decodeToken()).toBeResolvedTo(jasmine.anything()); + }); +}); + diff --git a/projects/angular-jwt/src/lib/jwthelper.service.ts b/projects/angular-jwt/src/lib/jwthelper.service.ts index c206e3ec..6234b861 100644 --- a/projects/angular-jwt/src/lib/jwthelper.service.ts +++ b/projects/angular-jwt/src/lib/jwthelper.service.ts @@ -6,7 +6,7 @@ import { JWT_OPTIONS } from './jwtoptions.token'; @Injectable() export class JwtHelperService { - tokenGetter: () => string; + tokenGetter: () => string | Promise; constructor(@Inject(JWT_OPTIONS) config = null) { this.tokenGetter = (config && config.tokenGetter) || function () {}; @@ -77,7 +77,17 @@ export class JwtHelperService { ); } - public decodeToken(token: string = this.tokenGetter()): T { + public decodeToken(token: string = null): T | Promise { + let _token = token || this.tokenGetter(); + + if (_token instanceof Promise) { + return _token.then(t => this._decodeToken(t)); + } + + return this._decodeToken(_token); + } + + private _decodeToken(token: string) { if (!token || token === '') { return null; } @@ -99,8 +109,19 @@ export class JwtHelperService { } public getTokenExpirationDate( - token: string = this.tokenGetter() - ): Date | null { + token: string = null + ): Date | null | Promise { + + const _token = token || this.tokenGetter(); + + if (_token instanceof Promise) { + return _token.then(t => this._getTokenExpirationDate(t)); + } + + return this._getTokenExpirationDate(_token); + } + + private _getTokenExpirationDate(token : string) { let decoded: any; decoded = this.decodeToken(token); @@ -115,7 +136,20 @@ export class JwtHelperService { } public isTokenExpired( - token: string = this.tokenGetter(), + token: string = null, + offsetSeconds?: number + ): boolean | Promise { + const _token = token || this.tokenGetter(); + + if (_token instanceof Promise) { + return _token.then(t => this._isTokenExpired(t, offsetSeconds)); + } + + return this._isTokenExpired(_token, offsetSeconds); + } + + public _isTokenExpired( + token: string, offsetSeconds?: number ): boolean { if (!token || token === '') { diff --git a/src/app/services/example-http.service.spec.ts b/src/app/services/example-http.service.spec.ts index 8d38e365..530d0c23 100644 --- a/src/app/services/example-http.service.spec.ts +++ b/src/app/services/example-http.service.spec.ts @@ -1,4 +1,4 @@ -import { TestBed } from '@angular/core/testing'; +import { fakeAsync, flush, TestBed } from '@angular/core/testing'; import { ExampleHttpService } from './example-http.service'; import { HttpClientTestingModule, @@ -22,6 +22,89 @@ export function tokenGetterWithRequest(request) { return 'TEST_TOKEN'; } +export function tokenGetterWithPromise() { + return Promise.resolve('TEST_TOKEN') +} + +describe('Example HttpService: with promise based tokken getter', () => { + let service: ExampleHttpService; + let httpMock: HttpTestingController; + + const validRoutes = [ + `/assets/example-resource.json`, + `http://allowed.com/api/`, + `http://allowed.com/api/test`, + `http://allowed.com:443/api/test`, + `http://allowed-regex.com/api/`, + `https://allowed-regex.com/api/`, + `http://localhost:3000`, + `http://localhost:3000/api`, + ]; + const invalidRoutes = [ + `http://allowed.com/api/disallowed`, + `http://allowed.com/api/disallowed-protocol`, + `http://allowed.com:80/api/disallowed-protocol`, + `http://allowed.com/api/disallowed-regex`, + `http://allowed-regex.com/api/disallowed-regex`, + `http://foo.com/bar`, + 'http://localhost/api', + 'http://localhost:4000/api', + ]; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [ + HttpClientTestingModule, + JwtModule.forRoot({ + config: { + tokenGetter: tokenGetterWithPromise, + allowedDomains: ['allowed.com', /allowed-regex*/, 'localhost:3000'], + disallowedRoutes: [ + 'http://allowed.com/api/disallowed-protocol', + '//allowed.com/api/disallowed', + /disallowed-regex*/, + ], + }, + }), + ], + }); + service = TestBed.get(ExampleHttpService); + httpMock = TestBed.get(HttpTestingController); + }); + + it('should add Authorisation header', () => { + expect(service).toBeTruthy(); + }); + + validRoutes.forEach((route) => + it(`should set the correct auth token for a allowed domain: ${route}`, fakeAsync(() => { + service.testRequest(route).subscribe((response) => { + expect(response).toBeTruthy(); + }); + + flush(); + const httpRequest = httpMock.expectOne(route); + + expect(httpRequest.request.headers.has('Authorization')).toEqual(true); + expect(httpRequest.request.headers.get('Authorization')).toEqual( + `Bearer TEST_TOKEN` + ); + })) + ); + + invalidRoutes.forEach((route) => + it(`should not set the auth token for a disallowed route: ${route}`, fakeAsync(() => { + service.testRequest(route).subscribe((response) => { + expect(response).toBeTruthy(); + }); + + flush(); + const httpRequest = httpMock.expectOne(route); + expect(httpRequest.request.headers.has('Authorization')).toEqual(false); + }) + )); +}); + describe('Example HttpService: with simple tokken getter', () => { let service: ExampleHttpService; let httpMock: HttpTestingController; From f1cfe511d1428db4b5eff759b154aefad789acb9 Mon Sep 17 00:00:00 2001 From: frederikprijck Date: Mon, 12 Dec 2022 16:58:19 +0100 Subject: [PATCH 2/5] Revert doublequotes --- .../angular-jwt/src/lib/jwt.interceptor.ts | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/projects/angular-jwt/src/lib/jwt.interceptor.ts b/projects/angular-jwt/src/lib/jwt.interceptor.ts index b7012424..698fad85 100644 --- a/projects/angular-jwt/src/lib/jwt.interceptor.ts +++ b/projects/angular-jwt/src/lib/jwt.interceptor.ts @@ -1,16 +1,16 @@ -import { Injectable, Inject } from "@angular/core"; +import { Injectable, Inject } from '@angular/core'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, -} from "@angular/common/http"; -import { DOCUMENT } from "@angular/common"; -import { JwtHelperService } from "./jwthelper.service"; -import { JWT_OPTIONS } from "./jwtoptions.token"; +} from '@angular/common/http'; +import { DOCUMENT } from '@angular/common'; +import { JwtHelperService } from './jwthelper.service'; +import { JWT_OPTIONS } from './jwtoptions.token'; -import { map, mergeMap } from "rxjs/operators"; -import { defer, from, Observable, of } from "rxjs"; +import { map, mergeMap } from 'rxjs/operators'; +import { defer, from, Observable, of } from 'rxjs'; const fromPromiseOrValue = (input: T | Promise) => { if (input instanceof Promise) { @@ -29,7 +29,7 @@ export class JwtInterceptor implements HttpInterceptor { disallowedRoutes: Array; throwNoTokenError: boolean; skipWhenExpired: boolean; - standardPorts: string[] = ["80", "443"]; + standardPorts: string[] = ['80', '443']; constructor( @Inject(JWT_OPTIONS) config: any, @@ -37,11 +37,11 @@ export class JwtInterceptor implements HttpInterceptor { @Inject(DOCUMENT) private document: Document ) { this.tokenGetter = config.tokenGetter; - this.headerName = config.headerName || "Authorization"; + this.headerName = config.headerName || 'Authorization'; this.authScheme = - config.authScheme || config.authScheme === "" + config.authScheme || config.authScheme === '' ? config.authScheme - : "Bearer "; + : 'Bearer '; this.allowedDomains = config.allowedDomains || []; this.disallowedRoutes = config.disallowedRoutes || []; this.throwNoTokenError = config.throwNoTokenError || false; @@ -60,13 +60,13 @@ export class JwtInterceptor implements HttpInterceptor { // If not the current domain, check the allowed list const hostName = `${requestUrl.hostname}${ requestUrl.port && !this.standardPorts.includes(requestUrl.port) - ? ":" + requestUrl.port - : "" + ? ':' + requestUrl.port + : '' }`; return ( this.allowedDomains.findIndex((domain) => - typeof domain === "string" + typeof domain === 'string' ? domain === hostName : domain instanceof RegExp ? domain.test(hostName) @@ -83,7 +83,7 @@ export class JwtInterceptor implements HttpInterceptor { return ( this.disallowedRoutes.findIndex((route: string | RegExp) => { - if (typeof route === "string") { + if (typeof route === 'string') { const parsedRoute: URL = new URL( route, this.document.location.origin @@ -111,7 +111,7 @@ export class JwtInterceptor implements HttpInterceptor { const authScheme = this.jwtHelper.getAuthScheme(this.authScheme, request); if (!token && this.throwNoTokenError) { - throw new Error("Could not get token from tokenGetter function."); + throw new Error('Could not get token from tokenGetter function.'); } if (token) { From 7a733253fb36fbf3e0f1771fc560b49e06058cb5 Mon Sep 17 00:00:00 2001 From: frederikprijck Date: Mon, 12 Dec 2022 17:05:33 +0100 Subject: [PATCH 3/5] Fix lint issues --- projects/angular-jwt/src/lib/jwt.interceptor.ts | 2 +- projects/angular-jwt/src/lib/jwthelper.service.spec.ts | 4 ++-- projects/angular-jwt/src/lib/jwthelper.service.ts | 4 ++-- src/app/services/example-http.service.spec.ts | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/projects/angular-jwt/src/lib/jwt.interceptor.ts b/projects/angular-jwt/src/lib/jwt.interceptor.ts index 698fad85..fd2d1575 100644 --- a/projects/angular-jwt/src/lib/jwt.interceptor.ts +++ b/projects/angular-jwt/src/lib/jwt.interceptor.ts @@ -125,7 +125,7 @@ export class JwtInterceptor implements HttpInterceptor { }, }) ), - mergeMap((request) => next.handle(request)) + mergeMap((innerRequest) => next.handle(innerRequest)) ); } diff --git a/projects/angular-jwt/src/lib/jwthelper.service.spec.ts b/projects/angular-jwt/src/lib/jwthelper.service.spec.ts index 81128489..24d9a5a3 100644 --- a/projects/angular-jwt/src/lib/jwthelper.service.spec.ts +++ b/projects/angular-jwt/src/lib/jwthelper.service.spec.ts @@ -6,7 +6,7 @@ import { JwtModule, JwtHelperService } from 'angular-jwt'; describe('Example HttpService: with simple based tokken getter', () => { let service: JwtHelperService; - let tokenGetter = jasmine.createSpy('tokenGetter'); + const tokenGetter = jasmine.createSpy('tokenGetter'); beforeEach(() => { TestBed.configureTestingModule({ @@ -44,7 +44,7 @@ describe('Example HttpService: with simple based tokken getter', () => { describe('Example HttpService: with a promise based tokken getter', () => { let service: JwtHelperService; - let tokenGetter = jasmine.createSpy('tokenGetter'); + const tokenGetter = jasmine.createSpy('tokenGetter'); beforeEach(() => { TestBed.configureTestingModule({ diff --git a/projects/angular-jwt/src/lib/jwthelper.service.ts b/projects/angular-jwt/src/lib/jwthelper.service.ts index 6234b861..535f5555 100644 --- a/projects/angular-jwt/src/lib/jwthelper.service.ts +++ b/projects/angular-jwt/src/lib/jwthelper.service.ts @@ -78,7 +78,7 @@ export class JwtHelperService { } public decodeToken(token: string = null): T | Promise { - let _token = token || this.tokenGetter(); + const _token = token || this.tokenGetter(); if (_token instanceof Promise) { return _token.then(t => this._decodeToken(t)); @@ -121,7 +121,7 @@ export class JwtHelperService { return this._getTokenExpirationDate(_token); } - private _getTokenExpirationDate(token : string) { + private _getTokenExpirationDate(token: string) { let decoded: any; decoded = this.decodeToken(token); diff --git a/src/app/services/example-http.service.spec.ts b/src/app/services/example-http.service.spec.ts index 530d0c23..3ee814c0 100644 --- a/src/app/services/example-http.service.spec.ts +++ b/src/app/services/example-http.service.spec.ts @@ -23,7 +23,7 @@ export function tokenGetterWithRequest(request) { } export function tokenGetterWithPromise() { - return Promise.resolve('TEST_TOKEN') + return Promise.resolve('TEST_TOKEN'); } describe('Example HttpService: with promise based tokken getter', () => { From fb21de64b5c3ea0522292a53cd1e2fd7f8d0d1c3 Mon Sep 17 00:00:00 2001 From: frederikprijck Date: Mon, 12 Dec 2022 17:35:25 +0100 Subject: [PATCH 4/5] Fix tests --- src/app/services/example-http.service.spec.ts | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/app/services/example-http.service.spec.ts b/src/app/services/example-http.service.spec.ts index 3ee814c0..58ab3c8e 100644 --- a/src/app/services/example-http.service.spec.ts +++ b/src/app/services/example-http.service.spec.ts @@ -6,24 +6,28 @@ import { } from '@angular/common/http/testing'; import { JwtModule } from 'angular-jwt'; +const TEST_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; +const TEST_TOKEN_1 = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.cMErWtEf7DxCXJl8C9q0L7ttkm-Ex54UWHsOCMGbtUc'; +const TEST_TOKEN_2 = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikphc29uIERvZSIsImlhdCI6MTUxNjIzOTAyMn0.f2z_alWh9QWCkPHtAdVMRlZOb_2krfZ1wd78Bj2_YEg'; + export function tokenGetter() { - return 'TEST_TOKEN'; + return TEST_TOKEN; } export function tokenGetterWithRequest(request) { if (request.url.includes('1')) { - return 'TEST_TOKEN_1'; + return TEST_TOKEN_1; } if (request.url.includes('2')) { - return 'TEST_TOKEN_2'; + return TEST_TOKEN_2; } - return 'TEST_TOKEN'; + return TEST_TOKEN; } export function tokenGetterWithPromise() { - return Promise.resolve('TEST_TOKEN'); + return Promise.resolve(TEST_TOKEN); } describe('Example HttpService: with promise based tokken getter', () => { @@ -87,7 +91,7 @@ describe('Example HttpService: with promise based tokken getter', () => { expect(httpRequest.request.headers.has('Authorization')).toEqual(true); expect(httpRequest.request.headers.get('Authorization')).toEqual( - `Bearer TEST_TOKEN` + `Bearer ${TEST_TOKEN}` ); })) ); From 9fe1af473af069247f30e510b7d47def97d6a2d3 Mon Sep 17 00:00:00 2001 From: frederikprijck Date: Mon, 12 Dec 2022 18:20:21 +0100 Subject: [PATCH 5/5] fix tests --- projects/angular-jwt/src/lib/jwt.interceptor.ts | 8 +++++++- src/app/services/example-http.service.spec.ts | 16 ++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/projects/angular-jwt/src/lib/jwt.interceptor.ts b/projects/angular-jwt/src/lib/jwt.interceptor.ts index fd2d1575..a6f8dbb0 100644 --- a/projects/angular-jwt/src/lib/jwt.interceptor.ts +++ b/projects/angular-jwt/src/lib/jwt.interceptor.ts @@ -114,8 +114,14 @@ export class JwtInterceptor implements HttpInterceptor { throw new Error('Could not get token from tokenGetter function.'); } + let tokenIsExpired = of(false); + + if (this.skipWhenExpired) { + tokenIsExpired = token ? fromPromiseOrValue(this.jwtHelper.isTokenExpired(token)) : of(true); + } + if (token) { - return fromPromiseOrValue(this.jwtHelper._isTokenExpired(token)).pipe( + return tokenIsExpired.pipe( map((isExpired) => isExpired && this.skipWhenExpired ? request.clone() diff --git a/src/app/services/example-http.service.spec.ts b/src/app/services/example-http.service.spec.ts index 58ab3c8e..3ee814c0 100644 --- a/src/app/services/example-http.service.spec.ts +++ b/src/app/services/example-http.service.spec.ts @@ -6,28 +6,24 @@ import { } from '@angular/common/http/testing'; import { JwtModule } from 'angular-jwt'; -const TEST_TOKEN = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; -const TEST_TOKEN_1 = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkphbmUgRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.cMErWtEf7DxCXJl8C9q0L7ttkm-Ex54UWHsOCMGbtUc'; -const TEST_TOKEN_2 = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6Ikphc29uIERvZSIsImlhdCI6MTUxNjIzOTAyMn0.f2z_alWh9QWCkPHtAdVMRlZOb_2krfZ1wd78Bj2_YEg'; - export function tokenGetter() { - return TEST_TOKEN; + return 'TEST_TOKEN'; } export function tokenGetterWithRequest(request) { if (request.url.includes('1')) { - return TEST_TOKEN_1; + return 'TEST_TOKEN_1'; } if (request.url.includes('2')) { - return TEST_TOKEN_2; + return 'TEST_TOKEN_2'; } - return TEST_TOKEN; + return 'TEST_TOKEN'; } export function tokenGetterWithPromise() { - return Promise.resolve(TEST_TOKEN); + return Promise.resolve('TEST_TOKEN'); } describe('Example HttpService: with promise based tokken getter', () => { @@ -91,7 +87,7 @@ describe('Example HttpService: with promise based tokken getter', () => { expect(httpRequest.request.headers.has('Authorization')).toEqual(true); expect(httpRequest.request.headers.get('Authorization')).toEqual( - `Bearer ${TEST_TOKEN}` + `Bearer TEST_TOKEN` ); })) );