supaapps-auth 2.0.0-rc.4 → 2.0.0-rc.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,4 +1,4 @@
1
- import { AuthManagerEvent } from './types';
1
+ import { AuthManagerEvent, UserTokenPayload } from './types';
2
2
  export declare class AuthManager {
3
3
  private static instance;
4
4
  private authServer;
@@ -21,6 +21,6 @@ export declare class AuthManager {
21
21
  private saveTokens;
22
22
  loginUsingPkce(code: string): Promise<void>;
23
23
  logout(): Promise<void>;
24
- static validateToken(authServer: string, bearerToken: string): Promise<boolean>;
24
+ static validateToken(authServer: string, bearerToken: string): Promise<UserTokenPayload>;
25
25
  static resetInstance(): void;
26
26
  }
@@ -90,7 +90,7 @@ class AuthManager {
90
90
  checkAccessToken() {
91
91
  return __awaiter(this, arguments, void 0, function* (isInitilization = false) {
92
92
  const accessToken = localStorage.getItem('access_token');
93
- if (accessToken || this.isTokenExpired(accessToken)) {
93
+ if (accessToken && this.isTokenExpired(accessToken)) {
94
94
  return this.refreshAccessToken(isInitilization);
95
95
  }
96
96
  return accessToken;
@@ -192,23 +192,34 @@ class AuthManager {
192
192
  return __awaiter(this, void 0, void 0, function* () {
193
193
  var _a;
194
194
  // @todo tests missing for this static validation
195
- try {
196
- const decodedToken = (_a = (0, jsonwebtoken_1.decode)(bearerToken, {
197
- complete: true,
198
- })) === null || _a === void 0 ? void 0 : _a.payload;
199
- if (!decodedToken) {
200
- return false;
201
- }
202
- const { data: publicKey } = yield axios_1.default.get(`${authServer}public/public_key`);
203
- const { data: algo } = yield axios_1.default.get(`${authServer}public/algo`);
204
- (0, jsonwebtoken_1.verify)(bearerToken, publicKey, { algorithms: [algo] });
205
- const { data: revokedIds } = yield axios_1.default.get(`${authServer}public/revoked_ids`);
206
- // eslint-disable-next-line @typescript-eslint/dot-notation
207
- return !revokedIds.includes(decodedToken['id']);
195
+ // @todo add caching for public key and algo
196
+ const decodedToken = (_a = (0, jsonwebtoken_1.decode)(bearerToken, {
197
+ complete: true,
198
+ })) === null || _a === void 0 ? void 0 : _a.payload;
199
+ if (!decodedToken) {
200
+ throw new Error('Not a valid jwt token');
208
201
  }
209
- catch (error) {
210
- return false;
202
+ const userToken = {
203
+ id: decodedToken['id'],
204
+ iss: decodedToken['iss'],
205
+ sub: parseInt(decodedToken['sub']),
206
+ first_name: decodedToken['first_name'],
207
+ last_name: decodedToken['last_name'],
208
+ email: decodedToken['email'],
209
+ aud: decodedToken['aud'],
210
+ iat: decodedToken['iat'],
211
+ exp: decodedToken['exp'],
212
+ scopes: decodedToken['scopes'],
213
+ realm: decodedToken['realm'],
214
+ };
215
+ const { data: publicKey } = yield axios_1.default.get(`${authServer}public/public_key`);
216
+ const { data: algo } = yield axios_1.default.get(`${authServer}public/algo`);
217
+ (0, jsonwebtoken_1.verify)(bearerToken, publicKey, { algorithms: [algo] });
218
+ const { data: revokedIds } = yield axios_1.default.get(`${authServer}public/revoked_ids`);
219
+ if (revokedIds.includes(decodedToken['id'])) {
220
+ throw new Error('Token is revoked');
211
221
  }
222
+ return userToken;
212
223
  });
213
224
  }
214
225
  static resetInstance() {
package/dist/types.d.ts CHANGED
@@ -18,6 +18,7 @@ export interface UserTokenPayload {
18
18
  iat: number;
19
19
  exp: number;
20
20
  scopes: string;
21
+ realm: string;
21
22
  }
22
23
  export interface AuthManagerEvent {
23
24
  type: AuthEventType;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supaapps-auth",
3
- "version": "2.0.0-rc.4",
3
+ "version": "2.0.0-rc.6",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -124,7 +124,7 @@ export class AuthManager {
124
124
 
125
125
  public async checkAccessToken(isInitilization: boolean = false): Promise<string> {
126
126
  const accessToken = localStorage.getItem('access_token');
127
- if (accessToken || this.isTokenExpired(accessToken)) {
127
+ if (accessToken && this.isTokenExpired(accessToken)) {
128
128
  return this.refreshAccessToken(isInitilization);
129
129
  }
130
130
  return accessToken;
@@ -230,34 +230,47 @@ export class AuthManager {
230
230
  public static async validateToken(
231
231
  authServer: string,
232
232
  bearerToken: string,
233
- ): Promise<boolean> {
233
+ ): Promise<UserTokenPayload> {
234
234
  // @todo tests missing for this static validation
235
- try {
236
- const decodedToken = jwtDecode(bearerToken, {
237
- complete: true,
238
- })?.payload;
235
+ // @todo add caching for public key and algo
236
+ const decodedToken = jwtDecode(bearerToken, {
237
+ complete: true,
238
+ })?.payload;
239
239
 
240
- if (!decodedToken) {
241
- return false;
242
- }
240
+ if (!decodedToken) {
241
+ throw new Error('Not a valid jwt token');
242
+ }
243
243
 
244
- const { data: publicKey } = await axios.get(
245
- `${authServer}public/public_key`,
246
- );
247
- const { data: algo } = await axios.get(
248
- `${authServer}public/algo`,
249
- );
244
+ const userToken: UserTokenPayload = {
245
+ id: decodedToken['id'],
246
+ iss: decodedToken['iss'],
247
+ sub: parseInt(decodedToken['sub'] as string),
248
+ first_name: decodedToken['first_name'],
249
+ last_name: decodedToken['last_name'],
250
+ email: decodedToken['email'],
251
+ aud: decodedToken['aud'],
252
+ iat: decodedToken['iat'],
253
+ exp: decodedToken['exp'],
254
+ scopes: decodedToken['scopes'],
255
+ realm: decodedToken['realm'],
256
+ }
250
257
 
251
- jwtVerify(bearerToken, publicKey, { algorithms: [algo] });
258
+ const { data: publicKey } = await axios.get(
259
+ `${authServer}public/public_key`,
260
+ );
261
+ const { data: algo } = await axios.get(
262
+ `${authServer}public/algo`,
263
+ );
252
264
 
253
- const { data: revokedIds } = await axios.get(
254
- `${authServer}public/revoked_ids`,
255
- );
256
- // eslint-disable-next-line @typescript-eslint/dot-notation
257
- return !revokedIds.includes(decodedToken['id']);
258
- } catch (error) {
259
- return false;
265
+ jwtVerify(bearerToken, publicKey, { algorithms: [algo] });
266
+
267
+ const { data: revokedIds } = await axios.get(
268
+ `${authServer}public/revoked_ids`,
269
+ );
270
+ if(revokedIds.includes(decodedToken['id'])){
271
+ throw new Error('Token is revoked');
260
272
  }
273
+ return userToken;
261
274
  }
262
275
 
263
276
  public static resetInstance(): void {
package/src/types.ts CHANGED
@@ -20,6 +20,7 @@ export interface UserTokenPayload {
20
20
  iat: number;
21
21
  exp: number;
22
22
  scopes: string;
23
+ realm: string;
23
24
  }
24
25
 
25
26
  export interface AuthManagerEvent {
@@ -12,7 +12,12 @@ const tokenThatWontExpire2 = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxM
12
12
  const tokenThatExpired = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiZmlyc3RfbmFtZSI6IkpvaG4gRG9lIiwibGFzdF9uYW1lIjoiRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJzY29wZXMiOiIvcm9vdC8qIiwiZXhwIjo1MDAsImlkIjoyLCJpc3MiOjEyMywiYXVkIjoidGVzdGluZyJ9.ungpbhHfCM5ZP5oiZ1RnMkJ-NKJI8s3_IPJptjyKHR4';
13
13
 
14
14
 
15
+
16
+
15
17
  describe('AuthManager Tests', () => {
18
+ beforeAll(() => {
19
+ jest.spyOn(localStorage, 'getItem');
20
+ });
16
21
 
17
22
  beforeEach(() => {
18
23
  localStorage.clear(); // Clear localStorage before each test
@@ -72,6 +77,26 @@ describe('AuthManager Tests', () => {
72
77
  });
73
78
 
74
79
 
80
+ describe('AuthManager Tests isolated ', () => {
81
+ it('doesn\'t refresh access token when its not expired', async () => {
82
+ const stateChange = jest.fn();
83
+
84
+
85
+ // check that we set localstorage correct
86
+ localStorage.setItem('access_token', tokenThatWontExpire1);
87
+ localStorage.setItem('refresh_token', 'mockRefreshToken');
88
+
89
+ const manager = AuthManager.initialize('http://auth-server.com/', 'example-realm', 'http://myapp.com/callback', stateChange);
90
+
91
+ const currentCallCount = (localStorage.getItem as jest.Mock).mock.calls.length;
92
+
93
+ const token = await manager.getAccessToken();
94
+
95
+ expect(localStorage.getItem).toHaveBeenCalledTimes(currentCallCount + 1);
96
+
97
+ });
98
+ });
99
+
75
100
  it('throws an error when no refresh token is found', async () => {
76
101
  localStorage.removeItem('refresh_token');
77
102
 
@@ -125,4 +150,4 @@ describe('AuthManager Tests', () => {
125
150
 
126
151
 
127
152
 
128
- });
153
+ });