supaapps-auth 2.0.0-rc.1 → 2.0.0-rc.10

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, Platforms, UserTokenPayload } from './types';
2
2
  export declare class AuthManager {
3
3
  private static instance;
4
4
  private authServer;
@@ -11,16 +11,24 @@ export declare class AuthManager {
11
11
  private tokenToPayload;
12
12
  private toBase64Url;
13
13
  private generatePKCEPair;
14
- refreshAccessToken(): Promise<string>;
15
- checkAccessToken(): Promise<string>;
14
+ refreshAccessToken(isInitialization?: boolean): Promise<string>;
15
+ checkAccessToken(isInitilization?: boolean): Promise<string>;
16
16
  private isTokenExpired;
17
17
  mustBeLoggedIn(): Promise<void>;
18
18
  getLoginWithGoogleUri(): string;
19
19
  isLoggedIn(): Promise<boolean>;
20
20
  getAccessToken(mustBeLoggedIn?: boolean): Promise<string>;
21
+ platformCheck(email: string): Promise<Array<Platforms>>;
22
+ verifyEmail(email: string, token: string): Promise<boolean>;
23
+ doPassReset(email: string, token: string, newPassword: string): Promise<boolean>;
24
+ changeEmail(email: string): Promise<boolean>;
25
+ initPasswordReset(email: string): Promise<boolean>;
26
+ changePassword(oldPassword: string, newPassword: string, email: string): Promise<boolean>;
27
+ registerUsingEmail(firstName: string, lastName: string, email: string, password: string): Promise<void>;
21
28
  private saveTokens;
29
+ loginUsingEmail(email: string, password: string): Promise<void>;
22
30
  loginUsingPkce(code: string): Promise<void>;
23
31
  logout(): Promise<void>;
24
- static validateToken(authServer: string, bearerToken: string): Promise<boolean>;
32
+ static validateToken(authServer: string, bearerToken: string): Promise<UserTokenPayload>;
25
33
  static resetInstance(): void;
26
34
  }
@@ -25,18 +25,18 @@ class AuthManager {
25
25
  static initialize(authServer, realmName, redirectUri, onStateChange) {
26
26
  if (!AuthManager.instance) {
27
27
  AuthManager.instance = new AuthManager(authServer, realmName, redirectUri, onStateChange);
28
- }
29
- AuthManager.instance
30
- .checkAccessToken()
31
- .then((token) => {
32
- onStateChange({
33
- type: types_1.AuthEventType.INITALIZED_IN,
34
- user: AuthManager.instance.tokenToPayload(token),
28
+ AuthManager.instance
29
+ .checkAccessToken(true)
30
+ .then((token) => {
31
+ onStateChange({
32
+ type: types_1.AuthEventType.INITALIZED_IN,
33
+ user: AuthManager.instance.tokenToPayload(token),
34
+ });
35
+ })
36
+ .catch(() => {
37
+ onStateChange({ type: types_1.AuthEventType.INITALIZED_OUT });
35
38
  });
36
- })
37
- .catch(() => {
38
- onStateChange({ type: types_1.AuthEventType.INITALIZED_OUT });
39
- });
39
+ }
40
40
  return AuthManager.instance;
41
41
  }
42
42
  static getInstance() {
@@ -63,7 +63,7 @@ class AuthManager {
63
63
  return { verifier, challenge };
64
64
  }
65
65
  refreshAccessToken() {
66
- return __awaiter(this, void 0, void 0, function* () {
66
+ return __awaiter(this, arguments, void 0, function* (isInitialization = false) {
67
67
  try {
68
68
  const refreshToken = localStorage.getItem('refresh_token');
69
69
  if (!refreshToken) {
@@ -79,16 +79,19 @@ class AuthManager {
79
79
  console.error(`Refresh token error, logging out: ${error}`);
80
80
  localStorage.removeItem('access_token');
81
81
  localStorage.removeItem('refresh_token');
82
- this.onStateChange({ type: types_1.AuthEventType.REFRESH_FAILED });
82
+ if (!isInitialization) {
83
+ // throw refresh fail only if not initialization
84
+ this.onStateChange({ type: types_1.AuthEventType.REFRESH_FAILED });
85
+ }
83
86
  throw error;
84
87
  }
85
88
  });
86
89
  }
87
90
  checkAccessToken() {
88
- return __awaiter(this, void 0, void 0, function* () {
91
+ return __awaiter(this, arguments, void 0, function* (isInitilization = false) {
89
92
  const accessToken = localStorage.getItem('access_token');
90
- if (accessToken || this.isTokenExpired(accessToken)) {
91
- return this.refreshAccessToken();
93
+ if (accessToken && this.isTokenExpired(accessToken)) {
94
+ return this.refreshAccessToken(isInitilization);
92
95
  }
93
96
  return accessToken;
94
97
  });
@@ -136,6 +139,113 @@ class AuthManager {
136
139
  }
137
140
  });
138
141
  }
142
+ platformCheck(email) {
143
+ return __awaiter(this, void 0, void 0, function* () {
144
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/platform_check`, {
145
+ realm_name: this.realmName,
146
+ email,
147
+ });
148
+ if (response.data.error || response.data.errors) {
149
+ throw new Error(response.data.error || response.data.message);
150
+ }
151
+ return (response.status === 200) ? response.data : { 'platforms': [] };
152
+ });
153
+ }
154
+ verifyEmail(email, token) {
155
+ return __awaiter(this, void 0, void 0, function* () {
156
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/verify`, {
157
+ realm_name: this.realmName,
158
+ email,
159
+ token,
160
+ });
161
+ if (response.data.error || response.data.errors) {
162
+ throw new Error(response.data.error || response.data.message);
163
+ }
164
+ return response.status === 200;
165
+ });
166
+ }
167
+ doPassReset(email, token, newPassword) {
168
+ return __awaiter(this, void 0, void 0, function* () {
169
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/do_pass_reset`, {
170
+ realm_name: this.realmName,
171
+ email,
172
+ token,
173
+ new_password: newPassword,
174
+ });
175
+ if (response.data.error || response.data.errors) {
176
+ throw new Error(response.data.error || response.data.message);
177
+ }
178
+ return response.status === 200;
179
+ });
180
+ }
181
+ changeEmail(email) {
182
+ return __awaiter(this, void 0, void 0, function* () {
183
+ const accessToken = localStorage.getItem('access_token');
184
+ if (!accessToken) {
185
+ throw new Error('Access token not found');
186
+ }
187
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/change_email`, {
188
+ realm_name: this.realmName,
189
+ email,
190
+ }, {
191
+ headers: { Authorization: `Bearer ${accessToken}` },
192
+ });
193
+ if (response.data.error || response.data.errors) {
194
+ throw new Error(response.data.error || response.data.message);
195
+ }
196
+ return response.status === 200;
197
+ });
198
+ }
199
+ initPasswordReset(email) {
200
+ return __awaiter(this, void 0, void 0, function* () {
201
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/init_pass_reset`, {
202
+ realm_name: this.realmName,
203
+ email,
204
+ });
205
+ if (response.data.error || response.data.errors) {
206
+ throw new Error(response.data.error || response.data.message);
207
+ }
208
+ return response.status === 200 || response.status === 201;
209
+ });
210
+ }
211
+ changePassword(oldPassword, newPassword, email) {
212
+ return __awaiter(this, void 0, void 0, function* () {
213
+ const accessToken = localStorage.getItem('access_token');
214
+ if (!accessToken) {
215
+ throw new Error('Access token not found');
216
+ }
217
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/change_pass`, {
218
+ realm_name: this.realmName,
219
+ email,
220
+ old_password: oldPassword,
221
+ new_password: newPassword,
222
+ }, {
223
+ headers: { Authorization: `Bearer ${accessToken}` },
224
+ });
225
+ if (response.data.error || response.data.errors) {
226
+ throw new Error(response.data.error || response.data.message);
227
+ }
228
+ return response.status === 200;
229
+ });
230
+ }
231
+ registerUsingEmail(firstName, lastName, email, password) {
232
+ return __awaiter(this, void 0, void 0, function* () {
233
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/register`, {
234
+ realm_name: this.realmName,
235
+ first_name: firstName,
236
+ last_name: lastName,
237
+ email,
238
+ password,
239
+ });
240
+ if (response.data.message || response.data.error) {
241
+ throw new Error(response.data.message || response.data.error);
242
+ }
243
+ if (!response.data.access_token) {
244
+ throw new Error('Something went wrong');
245
+ }
246
+ this.saveTokens(response, false);
247
+ });
248
+ }
139
249
  saveTokens(response, byRefresh) {
140
250
  localStorage.setItem('access_token', response.data.access_token);
141
251
  localStorage.setItem('refresh_token', response.data.refresh_token);
@@ -146,6 +256,19 @@ class AuthManager {
146
256
  const user = this.tokenToPayload(response.data.access_token);
147
257
  localStorage.setItem('user', JSON.stringify(user));
148
258
  }
259
+ loginUsingEmail(email, password) {
260
+ return __awaiter(this, void 0, void 0, function* () {
261
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/login`, {
262
+ realm_name: this.realmName,
263
+ email,
264
+ password,
265
+ });
266
+ if (response.data.message || response.data.error) {
267
+ throw new Error(response.data.message || response.data.error);
268
+ }
269
+ this.saveTokens(response, false);
270
+ });
271
+ }
149
272
  loginUsingPkce(code) {
150
273
  return __awaiter(this, void 0, void 0, function* () {
151
274
  try {
@@ -189,23 +312,34 @@ class AuthManager {
189
312
  return __awaiter(this, void 0, void 0, function* () {
190
313
  var _a;
191
314
  // @todo tests missing for this static validation
192
- try {
193
- const decodedToken = (_a = (0, jsonwebtoken_1.decode)(bearerToken, {
194
- complete: true,
195
- })) === null || _a === void 0 ? void 0 : _a.payload;
196
- if (!decodedToken) {
197
- return false;
198
- }
199
- const { data: publicKey } = yield axios_1.default.get(`${authServer}public/public_key`);
200
- const { data: algo } = yield axios_1.default.get(`${authServer}public/algo`);
201
- (0, jsonwebtoken_1.verify)(bearerToken, publicKey, { algorithms: [algo] });
202
- const { data: revokedIds } = yield axios_1.default.get(`${authServer}public/revoked_ids`);
203
- // eslint-disable-next-line @typescript-eslint/dot-notation
204
- return !revokedIds.includes(decodedToken['id']);
315
+ // @todo add caching for public key and algo
316
+ const decodedToken = (_a = (0, jsonwebtoken_1.decode)(bearerToken, {
317
+ complete: true,
318
+ })) === null || _a === void 0 ? void 0 : _a.payload;
319
+ if (!decodedToken) {
320
+ throw new Error('Not a valid jwt token');
205
321
  }
206
- catch (error) {
207
- return false;
322
+ const userToken = {
323
+ id: decodedToken.id,
324
+ iss: decodedToken.iss,
325
+ sub: typeof decodedToken.sub === 'string' ? parseInt(decodedToken.sub) : decodedToken.sub,
326
+ first_name: decodedToken.first_name,
327
+ last_name: decodedToken.last_name,
328
+ email: decodedToken.email,
329
+ aud: decodedToken.aud,
330
+ iat: decodedToken.iat,
331
+ exp: decodedToken.exp,
332
+ scopes: decodedToken.scopes,
333
+ realm: decodedToken.realm,
334
+ };
335
+ const { data: publicKey } = yield axios_1.default.get(`${authServer}public/public_key`);
336
+ const { data: algo } = yield axios_1.default.get(`${authServer}public/algo`);
337
+ (0, jsonwebtoken_1.verify)(bearerToken, publicKey, { algorithms: [algo] });
338
+ const { data: revokedIds } = yield axios_1.default.get(`${authServer}public/revoked_ids`);
339
+ if (revokedIds.includes(decodedToken.id)) {
340
+ throw new Error('Token is revoked');
208
341
  }
342
+ return userToken;
209
343
  });
210
344
  }
211
345
  static resetInstance() {
package/dist/types.d.ts CHANGED
@@ -10,7 +10,7 @@ export declare enum AuthEventType {
10
10
  export interface UserTokenPayload {
11
11
  id: number;
12
12
  iss: string;
13
- sub: number;
13
+ sub: number | string;
14
14
  first_name: string;
15
15
  last_name: string;
16
16
  email: string;
@@ -18,8 +18,19 @@ 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;
24
25
  user?: UserTokenPayload;
25
26
  }
27
+ export declare enum Platforms {
28
+ PASSWORD = "password",
29
+ GOOGLE = "google",
30
+ FACEBOOK = "facebook",
31
+ TWITTER = "twitter",
32
+ GITHUB = "github",
33
+ APPLE = "apple",
34
+ LINKEDIN = "linkedin",
35
+ MICROSOFT = "microsoft"
36
+ }
package/dist/types.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.AuthEventType = void 0;
3
+ exports.Platforms = exports.AuthEventType = void 0;
4
4
  var AuthEventType;
5
5
  (function (AuthEventType) {
6
6
  AuthEventType["INITALIZED_IN"] = "initialized-logged-in";
@@ -11,3 +11,14 @@ var AuthEventType;
11
11
  AuthEventType["FAILED_MUST_LOGIN_CHECK"] = "failed-must-login";
12
12
  AuthEventType["REFRESH_FAILED"] = "refresh-failed";
13
13
  })(AuthEventType || (exports.AuthEventType = AuthEventType = {}));
14
+ var Platforms;
15
+ (function (Platforms) {
16
+ Platforms["PASSWORD"] = "password";
17
+ Platforms["GOOGLE"] = "google";
18
+ Platforms["FACEBOOK"] = "facebook";
19
+ Platforms["TWITTER"] = "twitter";
20
+ Platforms["GITHUB"] = "github";
21
+ Platforms["APPLE"] = "apple";
22
+ Platforms["LINKEDIN"] = "linkedin";
23
+ Platforms["MICROSOFT"] = "microsoft";
24
+ })(Platforms || (exports.Platforms = Platforms = {}));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supaapps-auth",
3
- "version": "2.0.0-rc.1",
3
+ "version": "2.0.0-rc.10",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -25,7 +25,7 @@
25
25
  "@typescript-eslint/eslint-plugin": "^6.21.0",
26
26
  "@typescript-eslint/parser": "^6.21.0",
27
27
  "axios-mock-adapter": "^1.22.0",
28
- "eslint": "^8.57.0",
28
+ "eslint": "^8.57.1",
29
29
  "eslint-config-airbnb-base": "^15.0.0",
30
30
  "eslint-config-airbnb-typescript": "^17.1.0",
31
31
  "eslint-config-next": "^13.5.6",
@@ -4,7 +4,7 @@ import {
4
4
  decode as jwtDecode,
5
5
  verify as jwtVerify,
6
6
  } from 'jsonwebtoken'; // Ensure jsonwebtoken is correctly imported
7
- import { AuthEventType, AuthManagerEvent, UserTokenPayload } from './types';
7
+ import {AuthEventType, AuthManagerEvent, Platforms, UserTokenPayload} from './types';
8
8
 
9
9
  export class AuthManager {
10
10
  private static instance: AuthManager | null = null;
@@ -43,9 +43,8 @@ export class AuthManager {
43
43
  redirectUri,
44
44
  onStateChange,
45
45
  );
46
- }
47
- AuthManager.instance
48
- .checkAccessToken()
46
+ AuthManager.instance
47
+ .checkAccessToken(true)
49
48
  .then((token) => {
50
49
  onStateChange({
51
50
  type: AuthEventType.INITALIZED_IN,
@@ -55,6 +54,7 @@ export class AuthManager {
55
54
  .catch(() => {
56
55
  onStateChange({ type: AuthEventType.INITALIZED_OUT });
57
56
  });
57
+ }
58
58
  return AuthManager.instance;
59
59
  }
60
60
 
@@ -95,7 +95,7 @@ export class AuthManager {
95
95
  return { verifier, challenge };
96
96
  }
97
97
 
98
- public async refreshAccessToken(): Promise<string> {
98
+ public async refreshAccessToken(isInitialization: boolean = false): Promise<string> {
99
99
  try {
100
100
  const refreshToken = localStorage.getItem('refresh_token');
101
101
  if (!refreshToken) {
@@ -114,15 +114,18 @@ export class AuthManager {
114
114
  console.error(`Refresh token error, logging out: ${error}`);
115
115
  localStorage.removeItem('access_token');
116
116
  localStorage.removeItem('refresh_token');
117
- this.onStateChange({ type: AuthEventType.REFRESH_FAILED });
117
+ if (!isInitialization) {
118
+ // throw refresh fail only if not initialization
119
+ this.onStateChange({ type: AuthEventType.REFRESH_FAILED });
120
+ }
118
121
  throw error;
119
122
  }
120
123
  }
121
124
 
122
- public async checkAccessToken(): Promise<string> {
125
+ public async checkAccessToken(isInitilization: boolean = false): Promise<string> {
123
126
  const accessToken = localStorage.getItem('access_token');
124
- if (accessToken || this.isTokenExpired(accessToken)) {
125
- return this.refreshAccessToken();
127
+ if (accessToken && this.isTokenExpired(accessToken)) {
128
+ return this.refreshAccessToken(isInitilization);
126
129
  }
127
130
  return accessToken;
128
131
  }
@@ -167,6 +170,143 @@ export class AuthManager {
167
170
  }
168
171
  }
169
172
 
173
+
174
+ public async platformCheck(email: string): Promise<Array<Platforms>> {
175
+ const response = await axios.post(
176
+ `${this.authServer}auth/email/platform_check`,
177
+ {
178
+ realm_name: this.realmName,
179
+ email,
180
+ },
181
+ );
182
+ if (response.data.error || response.data.errors) {
183
+ throw new Error(response.data.error || response.data.message);
184
+ }
185
+
186
+ return (response.status === 200) ? response.data : {'platforms': []};
187
+ }
188
+
189
+ public async verifyEmail(email: string, token: string): Promise<boolean> {
190
+ const response = await axios.post(
191
+ `${this.authServer}auth/email/verify`,
192
+ {
193
+ realm_name: this.realmName,
194
+ email,
195
+ token,
196
+ },
197
+ );
198
+ if (response.data.error || response.data.errors) {
199
+ throw new Error(response.data.error || response.data.message);
200
+ }
201
+
202
+ return response.status === 200;
203
+ }
204
+
205
+ public async doPassReset(email: string, token: string, newPassword: string): Promise<boolean> {
206
+ const response = await axios.post(
207
+ `${this.authServer}auth/email/do_pass_reset`,
208
+ {
209
+ realm_name: this.realmName,
210
+ email,
211
+ token,
212
+ new_password: newPassword,
213
+ },
214
+ );
215
+ if (response.data.error || response.data.errors) {
216
+ throw new Error(response.data.error || response.data.message);
217
+ }
218
+
219
+ return response.status === 200;
220
+ }
221
+
222
+ public async changeEmail(email: string): Promise<boolean> {
223
+ const accessToken = localStorage.getItem('access_token');
224
+ if (!accessToken) {
225
+ throw new Error('Access token not found');
226
+ }
227
+ const response = await axios.post(
228
+ `${this.authServer}auth/email/change_email`,
229
+ {
230
+ realm_name: this.realmName,
231
+ email,
232
+ },
233
+ {
234
+ headers: { Authorization: `Bearer ${accessToken}` },
235
+ },
236
+ );
237
+ if (response.data.error || response.data.errors) {
238
+ throw new Error(response.data.error || response.data.message);
239
+ }
240
+
241
+ return response.status === 200;
242
+ }
243
+
244
+ public async initPasswordReset(email: string): Promise<boolean> {
245
+ const response = await axios.post(
246
+ `${this.authServer}auth/email/init_pass_reset`,
247
+ {
248
+ realm_name: this.realmName,
249
+ email,
250
+ },
251
+ );
252
+ if (response.data.error || response.data.errors) {
253
+ throw new Error(response.data.error || response.data.message);
254
+ }
255
+
256
+ return response.status === 200 || response.status === 201;
257
+ }
258
+
259
+ public async changePassword(oldPassword: string, newPassword: string, email: string): Promise<boolean> {
260
+ const accessToken = localStorage.getItem('access_token');
261
+ if (!accessToken) {
262
+ throw new Error('Access token not found');
263
+ }
264
+ const response = await axios.post(
265
+ `${this.authServer}auth/email/change_pass`,
266
+ {
267
+ realm_name: this.realmName,
268
+ email,
269
+ old_password: oldPassword,
270
+ new_password: newPassword,
271
+ },
272
+ {
273
+ headers: { Authorization: `Bearer ${accessToken}` },
274
+ },
275
+ );
276
+ if (response.data.error || response.data.errors) {
277
+ throw new Error(response.data.error || response.data.message);
278
+ }
279
+
280
+ return response.status === 200;
281
+ }
282
+
283
+ public async registerUsingEmail(
284
+ firstName: string,
285
+ lastName: string,
286
+ email: string,
287
+ password: string
288
+ ): Promise<void> {
289
+ const response = await axios.post(
290
+ `${this.authServer}auth/email/register`,
291
+ {
292
+ realm_name: this.realmName,
293
+ first_name: firstName,
294
+ last_name: lastName,
295
+ email,
296
+ password,
297
+ },
298
+ );
299
+ if (response.data.message || response.data.error) {
300
+ throw new Error(response.data.message || response.data.error);
301
+ }
302
+
303
+ if (!response.data.access_token) {
304
+ throw new Error('Something went wrong');
305
+ }
306
+
307
+ this.saveTokens(response, false);
308
+ }
309
+
170
310
  private saveTokens(response: AxiosResponse, byRefresh: boolean): void {
171
311
  localStorage.setItem('access_token', response.data.access_token);
172
312
  localStorage.setItem(
@@ -181,6 +321,21 @@ export class AuthManager {
181
321
  localStorage.setItem('user', JSON.stringify(user));
182
322
  }
183
323
 
324
+ public async loginUsingEmail(email: string, password: string): Promise<void> {
325
+ const response = await axios.post(
326
+ `${this.authServer}auth/email/login`,
327
+ {
328
+ realm_name: this.realmName,
329
+ email,
330
+ password,
331
+ },
332
+ );
333
+ if (response.data.message || response.data.error) {
334
+ throw new Error(response.data.message || response.data.error);
335
+ }
336
+ this.saveTokens(response, false);
337
+ }
338
+
184
339
  public async loginUsingPkce(code: string): Promise<void> {
185
340
  try {
186
341
  const codeVerifier = localStorage.getItem('codeVerifier');
@@ -227,34 +382,47 @@ export class AuthManager {
227
382
  public static async validateToken(
228
383
  authServer: string,
229
384
  bearerToken: string,
230
- ): Promise<boolean> {
385
+ ): Promise<UserTokenPayload> {
231
386
  // @todo tests missing for this static validation
232
- try {
233
- const decodedToken = jwtDecode(bearerToken, {
234
- complete: true,
235
- })?.payload;
387
+ // @todo add caching for public key and algo
388
+ const decodedToken = jwtDecode(bearerToken, {
389
+ complete: true,
390
+ })?.payload as unknown as UserTokenPayload;
236
391
 
237
- if (!decodedToken) {
238
- return false;
239
- }
392
+ if (!decodedToken) {
393
+ throw new Error('Not a valid jwt token');
394
+ }
240
395
 
241
- const { data: publicKey } = await axios.get(
242
- `${authServer}public/public_key`,
243
- );
244
- const { data: algo } = await axios.get(
245
- `${authServer}public/algo`,
246
- );
396
+ const userToken: UserTokenPayload = {
397
+ id: decodedToken.id,
398
+ iss: decodedToken.iss,
399
+ sub: typeof decodedToken.sub === 'string' ? parseInt(decodedToken.sub) : decodedToken.sub,
400
+ first_name: decodedToken.first_name,
401
+ last_name: decodedToken.last_name,
402
+ email: decodedToken.email,
403
+ aud: decodedToken.aud,
404
+ iat: decodedToken.iat,
405
+ exp: decodedToken.exp,
406
+ scopes: decodedToken.scopes,
407
+ realm: decodedToken.realm,
408
+ }
247
409
 
248
- jwtVerify(bearerToken, publicKey, { algorithms: [algo] });
410
+ const { data: publicKey } = await axios.get(
411
+ `${authServer}public/public_key`,
412
+ );
413
+ const { data: algo } = await axios.get(
414
+ `${authServer}public/algo`,
415
+ );
249
416
 
250
- const { data: revokedIds } = await axios.get(
251
- `${authServer}public/revoked_ids`,
252
- );
253
- // eslint-disable-next-line @typescript-eslint/dot-notation
254
- return !revokedIds.includes(decodedToken['id']);
255
- } catch (error) {
256
- return false;
417
+ jwtVerify(bearerToken, publicKey, { algorithms: [algo] });
418
+
419
+ const { data: revokedIds } = await axios.get(
420
+ `${authServer}public/revoked_ids`,
421
+ );
422
+ if(revokedIds.includes(decodedToken.id)){
423
+ throw new Error('Token is revoked');
257
424
  }
425
+ return userToken;
258
426
  }
259
427
 
260
428
  public static resetInstance(): void {
package/src/types.ts CHANGED
@@ -12,7 +12,7 @@ export enum AuthEventType {
12
12
  export interface UserTokenPayload {
13
13
  id: number;
14
14
  iss: string;
15
- sub: number;
15
+ sub: number | string;
16
16
  first_name: string;
17
17
  last_name: string;
18
18
  email: string;
@@ -20,9 +20,21 @@ 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 {
26
27
  type: AuthEventType;
27
28
  user?: UserTokenPayload;
28
29
  }
30
+
31
+ export enum Platforms {
32
+ PASSWORD = 'password',
33
+ GOOGLE = 'google',
34
+ FACEBOOK = 'facebook',
35
+ TWITTER = 'twitter',
36
+ GITHUB = 'github',
37
+ APPLE = 'apple',
38
+ LINKEDIN = 'linkedin',
39
+ MICROSOFT = 'microsoft',
40
+ }
@@ -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
+ });