Skip to content

Commit 1c89636

Browse files
alain-charlesnnixaa
authored andcommitted
feat(auth): add a back link to the strategy name in the token (#571)
The token now contains `ownerStrategyName` field, which is a backlink to the strategy used to create the token. BREAKING CHANGE: `nbAuthCreateToken` (token.ts) function now takes a third parameter, which is the `ownerStrategyName`. Since `nbAuthCreateToken` is a part of public API this could *potentially* introduce a breaking change.
1 parent 9cbaa45 commit 1c89636

File tree

11 files changed

+111
-63
lines changed

11 files changed

+111
-63
lines changed

src/framework/auth/services/auth.spec.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ describe('auth-service', () => {
2424
let tokenService: NbTokenService;
2525
let dummyAuthStrategy: NbDummyAuthStrategy;
2626
const testTokenValue = 'test-token';
27+
const ownerStrategyName = 'strategy';
28+
2729

2830
const resp401 = new HttpResponse<Object>({body: {}, status: 401});
2931
const resp200 = new HttpResponse<Object>({body: {}, status: 200});
3032

31-
const testToken = nbAuthCreateToken(NbAuthSimpleToken, testTokenValue);
32-
const emptyToken = nbAuthCreateToken(NbAuthSimpleToken, null);
33+
const testToken = nbAuthCreateToken(NbAuthSimpleToken, testTokenValue, ownerStrategyName);
34+
const emptyToken = nbAuthCreateToken(NbAuthSimpleToken, null, ownerStrategyName);
3335

3436
const failResult = new NbAuthResult(false,
3537
resp401,

src/framework/auth/services/token/token-parceler.spec.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ import { NB_AUTH_TOKENS } from '../../auth.options';
1313
describe('token-parceler', () => {
1414

1515
let tokenParceler: NbAuthTokenParceler;
16-
const simpleToken = nbAuthCreateToken(NbAuthSimpleToken, 'test value');
17-
const wrappedSimple = `{"name":"${NbAuthSimpleToken.NAME}","value":"${simpleToken.getValue()}"}`;
16+
const simpleToken = nbAuthCreateToken(NbAuthSimpleToken, 'test value', 'strategy');
1817
// tslint:disable-next-line
19-
const jwtToken = nbAuthCreateToken(NbAuthJWTToken, 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzY290Y2guaW8iLCJleHAiOjI1MTczMTQwNjYxNzUsIm5hbWUiOiJDaHJpcyBTZXZpbGxlamEiLCJhZG1pbiI6dHJ1ZX0=.03f329983b86f7d9a9f5fef85305880101d5e302afafa20154d094b229f75773');
20-
const wrappedJWT = `{"name":"${NbAuthJWTToken.NAME}","value":"${jwtToken.getValue()}"}`;
21-
22-
const wrappedNonExisting = `{"name":"non-existing","value":"${simpleToken.getValue()}"}`;
18+
const wrappedSimple = `{"name":"${NbAuthSimpleToken.NAME}","ownerStrategyName":"${simpleToken.getOwnerStrategyName()}","value":"${simpleToken.getValue()}"}`;
19+
// tslint:disable-next-line
20+
const jwtToken = nbAuthCreateToken(NbAuthJWTToken, 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzY290Y2guaW8iLCJleHAiOjI1MTczMTQwNjYxNzUsIm5hbWUiOiJDaHJpcyBTZXZpbGxlamEiLCJhZG1pbiI6dHJ1ZX0=.03f329983b86f7d9a9f5fef85305880101d5e302afafa20154d094b229f75773', 'strategy');
21+
// tslint:disable-next-line
22+
const wrappedJWT = `{"name":"${NbAuthJWTToken.NAME}","ownerStrategyName":"${jwtToken.getOwnerStrategyName()}","value":"${jwtToken.getValue()}"}`;
23+
// tslint:disable-next-line
24+
const wrappedNonExisting = `{"name":"non-existing","value":"${simpleToken.getValue()}","ownerStrategyName":"${simpleToken.getOwnerStrategyName()}"}`;
2325
const wrappedInvalid = `{"name":"non-existing"`;
2426

2527
describe('default configuration', () => {

src/framework/auth/services/token/token-parceler.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { NB_AUTH_TOKENS } from '../../auth.options';
55

66
export interface NbTokenPack {
77
name: string,
8+
ownerStrategyName: string,
89
value: string,
910
}
1011

@@ -23,21 +24,23 @@ export class NbAuthTokenParceler {
2324
wrap(token: NbAuthToken): string {
2425
return JSON.stringify({
2526
name: token.getName(),
27+
ownerStrategyName: token.getOwnerStrategyName(),
2628
value: token.toString(),
2729
});
2830
}
2931

3032
unwrap(value: string): NbAuthToken {
3133
let tokenClass: NbAuthTokenClass = this.fallbackClass;
3234
let tokenValue = '';
33-
35+
let tokenOwnerStrategyName = '';
3436
const tokenPack: NbTokenPack = this.parseTokenPack(value);
3537
if (tokenPack) {
3638
tokenClass = this.getClassByName(tokenPack.name) || this.fallbackClass;
3739
tokenValue = tokenPack.value;
40+
tokenOwnerStrategyName = tokenPack.ownerStrategyName;
3841
}
3942

40-
return nbAuthCreateToken(tokenClass, tokenValue);
43+
return nbAuthCreateToken(tokenClass, tokenValue, tokenOwnerStrategyName);
4144
}
4245

4346
// TODO: this could be moved to a separate token registry

src/framework/auth/services/token/token-service.spec.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ import { NB_AUTH_FALLBACK_TOKEN, NbAuthTokenParceler } from './token-parceler';
1515
import { NB_AUTH_TOKENS } from '../../auth.options';
1616

1717
const noop = () => {};
18+
const ownerStrategyName = 'strategy';
1819

1920
describe('token-service', () => {
2021

2122
let tokenService: NbTokenService;
2223
let tokenStorage: NbTokenLocalStorage;
23-
const simpleToken = nbAuthCreateToken(NbAuthSimpleToken, 'test value');
24-
const emptyToken = nbAuthCreateToken(NbAuthSimpleToken, '');
24+
const simpleToken = nbAuthCreateToken(NbAuthSimpleToken, 'test value', ownerStrategyName);
25+
const emptyToken = nbAuthCreateToken(NbAuthSimpleToken, '', ownerStrategyName);
2526
const testTokenKey = 'auth_app_token';
2627

2728
beforeEach(() => {

src/framework/auth/services/token/token-storage.spec.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ describe('token-storage', () => {
1818
let tokenParceler: NbAuthTokenParceler;
1919
const testTokenKey = 'auth_app_token';
2020
const testTokenValue = 'test-token';
21+
const ownerStrategyName = 'strategy';
2122

2223
beforeEach(() => {
2324
TestBed.configureTestingModule({
@@ -44,7 +45,7 @@ describe('token-storage', () => {
4445

4546

4647
it('set test token', () => {
47-
const token = nbAuthCreateToken(NbAuthSimpleToken, testTokenValue);
48+
const token = nbAuthCreateToken(NbAuthSimpleToken, testTokenValue, ownerStrategyName);
4849

4950
tokenStorage.set(token);
5051
expect(localStorage.getItem(testTokenKey)).toEqual(tokenParceler.wrap(token));
@@ -53,11 +54,11 @@ describe('token-storage', () => {
5354
it('setter set invalid token to localStorage as empty string', () => {
5455
let token;
5556

56-
token = nbAuthCreateToken(NbAuthSimpleToken, null);
57+
token = nbAuthCreateToken(NbAuthSimpleToken, null, ownerStrategyName);
5758
tokenStorage.set(token);
5859
expect(localStorage.getItem(testTokenKey)).toEqual(tokenParceler.wrap(token));
5960

60-
token = nbAuthCreateToken(NbAuthSimpleToken, undefined);
61+
token = nbAuthCreateToken(NbAuthSimpleToken, undefined, ownerStrategyName);
6162
tokenStorage.set(token);
6263
expect(localStorage.getItem(testTokenKey)).toEqual(tokenParceler.wrap(token));
6364
});
@@ -69,14 +70,14 @@ describe('token-storage', () => {
6970
});
7071

7172
it('should return correct value', () => {
72-
const token = nbAuthCreateToken(NbAuthSimpleToken, 'test');
73+
const token = nbAuthCreateToken(NbAuthSimpleToken, 'test', ownerStrategyName);
7374
localStorage.setItem(testTokenKey, tokenParceler.wrap(token));
7475

7576
expect(tokenStorage.get().getValue()).toEqual(token.getValue());
7677
});
7778

7879
it('clear remove token', () => {
79-
const token = nbAuthCreateToken(NbAuthSimpleToken, 'test');
80+
const token = nbAuthCreateToken(NbAuthSimpleToken, 'test', ownerStrategyName);
8081
localStorage.setItem(testTokenKey, tokenParceler.wrap(token));
8182

8283
tokenStorage.clear();
@@ -85,7 +86,7 @@ describe('token-storage', () => {
8586
});
8687

8788
it('clear remove token only', () => {
88-
const token = nbAuthCreateToken(NbAuthSimpleToken, 'test');
89+
const token = nbAuthCreateToken(NbAuthSimpleToken, 'test', ownerStrategyName);
8990
localStorage.setItem(testTokenKey, tokenParceler.wrap(token));
9091
localStorage.setItem(testTokenKey + '2', tokenParceler.wrap(token));
9192

src/framework/auth/services/token/token.spec.ts

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@ import { NbAuthOAuth2Token, NbAuthJWTToken, NbAuthSimpleToken } from './token';
1010
describe('auth token', () => {
1111
describe('NbAuthJWTToken', () => {
1212
// tslint:disable
13-
const simpleToken = new NbAuthSimpleToken('token');
14-
const validJWTToken = new NbAuthJWTToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzY290Y2guaW8iLCJleHAiOjI1MTczMTQwNjYxNzUsIm5hbWUiOiJDaHJpcyBTZXZpbGxlamEiLCJhZG1pbiI6dHJ1ZX0=.03f329983b86f7d9a9f5fef85305880101d5e302afafa20154d094b229f75773');
15-
const emptyJWTToken = new NbAuthJWTToken('..');
16-
const invalidBase64JWTToken = new NbAuthJWTToken('h%2BHY.h%2BHY.h%2BHY');
13+
const simpleToken = new NbAuthSimpleToken('token','strategy');
14+
const validJWTToken = new NbAuthJWTToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzY290Y2guaW8iLCJleHAiOjI1MTczMTQwNjYxNzUsIm5hbWUiOiJDaHJpcyBTZXZpbGxlamEiLCJhZG1pbiI6dHJ1ZX0=.03f329983b86f7d9a9f5fef85305880101d5e302afafa20154d094b229f75773', 'strategy');
15+
const emptyJWTToken = new NbAuthJWTToken('..', 'strategy');
16+
const invalidBase64JWTToken = new NbAuthJWTToken('h%2BHY.h%2BHY.h%2BHY','strategy');
1717

18-
const invalidJWTToken = new NbAuthJWTToken('.');
18+
const invalidJWTToken = new NbAuthJWTToken('.','strategy');
1919

20-
const noExpJWTToken = new NbAuthJWTToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzY290Y2guaW8iLCJuYW1lIjoiQ2hyaXMgU2V2aWxsZWphIiwiYWRtaW4iOnRydWV9.03f329983b86f7d9a9f5fef85305880101d5e302afafa20154d094b229f75773');
20+
const noExpJWTToken = new NbAuthJWTToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzY290Y2guaW8iLCJuYW1lIjoiQ2hyaXMgU2V2aWxsZWphIiwiYWRtaW4iOnRydWV9.03f329983b86f7d9a9f5fef85305880101d5e302afafa20154d094b229f75773','strategy');
2121

22-
const expiredJWTToken = new NbAuthJWTToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzY290Y2guaW8iLCJleHAiOjEzMDA4MTkzODAsIm5hbWUiOiJDaHJpcyBTZXZpbGxlamEiLCJhZG1pbiI6dHJ1ZX0.03f329983b86f7d9a9f5fef85305880101d5e302afafa20154d094b229f75773');
22+
const expiredJWTToken = new NbAuthJWTToken('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzY290Y2guaW8iLCJleHAiOjEzMDA4MTkzODAsIm5hbWUiOiJDaHJpcyBTZXZpbGxlamEiLCJhZG1pbiI6dHJ1ZX0.03f329983b86f7d9a9f5fef85305880101d5e302afafa20154d094b229f75773','strategy');
2323
// tslint:enable
2424

2525
it('getPayload success', () => {
@@ -71,7 +71,7 @@ describe('auth token', () => {
7171

7272
it('isValid fail', () => {
7373
// without token
74-
expect(new NbAuthJWTToken('').isValid()).toBeFalsy();
74+
expect(new NbAuthJWTToken('', 'strategy').isValid()).toBeFalsy();
7575

7676
// expired date
7777
expect(expiredJWTToken.isValid()).toBeFalsy();
@@ -123,14 +123,14 @@ describe('auth token', () => {
123123
example_parameter: 'example_value',
124124
};
125125

126-
const validToken = new NbAuthOAuth2Token(token);
127-
const emptyToken = new NbAuthOAuth2Token({});
126+
const validToken = new NbAuthOAuth2Token(token, 'strategy');
127+
const emptyToken = new NbAuthOAuth2Token({}, 'strategy');
128128

129129
const noExpToken = new NbAuthOAuth2Token({
130130
access_token: '2YotnFZFEjr1zCsicMWpAA',
131131
refresh_token: 'tGzv3JOkF0XG5Qx2TlKWIA',
132132
example_parameter: 'example_value',
133-
});
133+
}, 'strategy');
134134

135135
it('getPayload success', () => {
136136
expect(validToken.getPayload()).toEqual(token);

src/framework/auth/services/token/token.ts

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ export abstract class NbAuthToken {
44
abstract getValue(): string;
55
abstract isValid(): boolean;
66
abstract getPayload(): string;
7+
// the strategy name used to acquire this token (needed for refreshing token)
8+
abstract getOwnerStrategyName(): string;
79
abstract toString(): string;
810

911
getName(): string {
@@ -17,11 +19,13 @@ export interface NbAuthRefreshableToken {
1719

1820
export interface NbAuthTokenClass {
1921
NAME: string;
20-
new (raw: any): NbAuthToken;
22+
new (raw: any, ownerStrategyName: string): NbAuthToken;
2123
}
2224

23-
export function nbAuthCreateToken(tokenClass: NbAuthTokenClass, token: any) {
24-
return new tokenClass(token);
25+
export function nbAuthCreateToken(tokenClass: NbAuthTokenClass,
26+
token: any,
27+
ownerStrategyName: string) {
28+
return new tokenClass(token, ownerStrategyName);
2529
}
2630

2731
/**
@@ -31,7 +35,8 @@ export class NbAuthSimpleToken extends NbAuthToken {
3135

3236
static NAME = 'nb:auth:simple:token';
3337

34-
constructor(protected readonly token: any) {
38+
constructor(protected readonly token: any,
39+
protected readonly ownerStrategyName: string) {
3540
super();
3641
}
3742

@@ -43,6 +48,10 @@ export class NbAuthSimpleToken extends NbAuthToken {
4348
return this.token;
4449
}
4550

51+
getOwnerStrategyName(): string {
52+
return this.ownerStrategyName;
53+
}
54+
4655
getPayload(): string {
4756
return null;
4857
}
@@ -142,9 +151,10 @@ export class NbAuthOAuth2Token extends NbAuthSimpleToken {
142151

143152
static NAME = 'nb:auth:oauth2:token';
144153

145-
constructor(protected data: { [key: string]: string|number }|string = {}) {
154+
constructor(protected data: { [key: string]: string|number }|string = {},
155+
protected ownerStrategyName: string) {
146156
// we may get it as string when retrieving from a storage
147-
super(prepareOAuth2Token(data));
157+
super(prepareOAuth2Token(data), ownerStrategyName);
148158
}
149159

150160
/**

src/framework/auth/strategies/auth-strategy.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export abstract class NbAuthStrategy {
2121
}
2222

2323
createToken(value: any): NbAuthToken {
24-
return nbAuthCreateToken(this.getOption('token.class'), value);
24+
return nbAuthCreateToken(this.getOption('token.class'), value, this.getName());
2525
}
2626

2727
getName(): string {

src/framework/auth/strategies/oauth2/oauth2-strategy.spec.ts

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ describe('oauth2-auth-strategy', () => {
4343
error_uri: 'some',
4444
};
4545

46-
const successToken = nbAuthCreateToken(NbAuthOAuth2Token, tokenSuccessResponse) as NbAuthOAuth2Token;
46+
const successToken = nbAuthCreateToken(NbAuthOAuth2Token, tokenSuccessResponse, 'strategy') as NbAuthOAuth2Token;
4747

4848

4949
beforeEach(() => {
@@ -78,6 +78,7 @@ describe('oauth2-auth-strategy', () => {
7878

7979
beforeEach(() => {
8080
strategy.setOptions({
81+
name: 'strategy',
8182
baseEndpoint: 'http://example.com/',
8283
clientId: 'clientId',
8384
clientSecret: 'clientSecret',
@@ -104,7 +105,8 @@ describe('oauth2-auth-strategy', () => {
104105
expect(result).toBeTruthy();
105106
expect(result.isSuccess()).toBe(true);
106107
expect(result.isFailure()).toBe(false);
107-
expect(result.getToken()).toEqual(successToken);
108+
expect(result.getToken().getValue()).toEqual(successToken.getValue());
109+
expect(result.getToken().getOwnerStrategyName()).toEqual(successToken.getOwnerStrategyName());
108110
expect(result.getMessages()).toEqual(successMessages);
109111
expect(result.getErrors()).toEqual([]); // no error message, response is success
110112
expect(result.getRedirect()).toEqual('/');
@@ -166,7 +168,8 @@ describe('oauth2-auth-strategy', () => {
166168
expect(result).toBeTruthy();
167169
expect(result.isSuccess()).toBe(true);
168170
expect(result.isFailure()).toBe(false);
169-
expect(result.getToken()).toEqual(successToken);
171+
expect(result.getToken().getValue()).toEqual(successToken.getValue());
172+
expect(result.getToken().getOwnerStrategyName()).toEqual(successToken.getOwnerStrategyName());
170173
expect(result.getMessages()).toEqual(successMessages);
171174
expect(result.getErrors()).toEqual([]); // no error message, response is success
172175
expect(result.getRedirect()).toEqual('/');
@@ -205,6 +208,7 @@ describe('oauth2-auth-strategy', () => {
205208

206209
beforeEach(() => {
207210
strategy.setOptions({
211+
name: 'strategy',
208212
baseEndpoint: 'http://example.com/',
209213
clientId: 'clientId',
210214
clientSecret: 'clientSecret',
@@ -236,7 +240,8 @@ describe('oauth2-auth-strategy', () => {
236240
expect(result).toBeTruthy();
237241
expect(result.isSuccess()).toBe(true);
238242
expect(result.isFailure()).toBe(false);
239-
expect(result.getToken()).toEqual(nbAuthCreateToken(NbAuthOAuth2Token, token));
243+
// tslint:disable-next-line
244+
expect(result.getToken().getValue()).toEqual(nbAuthCreateToken(NbAuthOAuth2Token, token, 'strategy').getValue());
240245
expect(result.getMessages()).toEqual(successMessages);
241246
expect(result.getErrors()).toEqual([]); // no error message, response is success
242247
expect(result.getRedirect()).toEqual('/');
@@ -266,6 +271,7 @@ describe('oauth2-auth-strategy', () => {
266271

267272
beforeEach(() => {
268273
strategy.setOptions({
274+
name: 'strategy',
269275
baseEndpoint: 'http://example.com/',
270276
clientId: 'clientId',
271277
clientSecret: 'clientSecret',
@@ -317,7 +323,8 @@ describe('oauth2-auth-strategy', () => {
317323
expect(result).toBeTruthy();
318324
expect(result.isSuccess()).toBe(true);
319325
expect(result.isFailure()).toBe(false);
320-
expect(result.getToken()).toEqual(successToken);
326+
expect(result.getToken().getValue()).toEqual(successToken.getValue());
327+
expect(result.getToken().getOwnerStrategyName()).toEqual(successToken.getOwnerStrategyName());
321328
expect(result.getMessages()).toEqual(successMessages);
322329
expect(result.getErrors()).toEqual([]); // no error message, response is success
323330
expect(result.getRedirect()).toEqual('/success');
@@ -341,7 +348,8 @@ describe('oauth2-auth-strategy', () => {
341348
expect(result).toBeTruthy();
342349
expect(result.isSuccess()).toBe(true);
343350
expect(result.isFailure()).toBe(false);
344-
expect(result.getToken()).toEqual(successToken);
351+
expect(result.getToken().getValue()).toEqual(successToken.getValue());
352+
expect(result.getToken().getOwnerStrategyName()).toEqual(successToken.getOwnerStrategyName());
345353
expect(result.getMessages()).toEqual(successMessages);
346354
expect(result.getErrors()).toEqual([]); // no error message, response is success
347355
expect(result.getRedirect()).toEqual('/success');
@@ -376,7 +384,8 @@ describe('oauth2-auth-strategy', () => {
376384
expect(result).toBeTruthy();
377385
expect(result.isSuccess()).toBe(true);
378386
expect(result.isFailure()).toBe(false);
379-
expect(result.getToken()).toEqual(successToken);
387+
expect(result.getToken().getValue()).toEqual(successToken.getValue());
388+
expect(result.getToken().getOwnerStrategyName()).toEqual(successToken.getOwnerStrategyName());
380389
expect(result.getMessages()).toEqual(successMessages);
381390
expect(result.getErrors()).toEqual([]); // no error message, response is success
382391
expect(result.getRedirect()).toEqual('/success');
@@ -417,6 +426,7 @@ describe('oauth2-auth-strategy', () => {
417426

418427
beforeEach(() => {
419428
strategy.setOptions({
429+
name: 'strategy',
420430
baseEndpoint: 'http://example.com/',
421431
clientId: 'clientId',
422432
clientSecret: 'clientSecret',
@@ -436,7 +446,8 @@ describe('oauth2-auth-strategy', () => {
436446
expect(result).toBeTruthy();
437447
expect(result.isSuccess()).toBe(true);
438448
expect(result.isFailure()).toBe(false);
439-
expect(result.getToken()).toEqual(successToken);
449+
expect(result.getToken().getValue()).toEqual(successToken.getValue());
450+
expect(result.getToken().getOwnerStrategyName()).toEqual(successToken.getOwnerStrategyName());
440451
expect(result.getMessages()).toEqual(successMessages);
441452
expect(result.getErrors()).toEqual([]); // no error message, response is success
442453
expect(result.getRedirect()).toEqual('/');

0 commit comments

Comments
 (0)