supaapps-auth 2.1.0 → 3.0.1
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.
- package/dist/index.d.ts +88 -2
- package/dist/index.js +475 -19
- package/package.json +25 -15
- package/.eslintrc +0 -3
- package/.github/workflows/ci.yml +0 -32
- package/.github/workflows/publish-to-npm.yml +0 -30
- package/.prettierrc +0 -7
- package/dist/AuthManager.d.ts +0 -47
- package/dist/AuthManager.js +0 -419
- package/dist/types.d.ts +0 -40
- package/dist/types.js +0 -24
- package/jest.config.js +0 -16
- package/src/AuthManager.ts +0 -556
- package/src/index.ts +0 -2
- package/src/types.ts +0 -45
- package/tests/AuthManager.test.ts +0 -153
- package/tsconfig.json +0 -9
package/src/AuthManager.ts
DELETED
|
@@ -1,556 +0,0 @@
|
|
|
1
|
-
import axios, { AxiosResponse } from 'axios';
|
|
2
|
-
import { createHash, randomBytes } from 'crypto';
|
|
3
|
-
import {
|
|
4
|
-
decode as jwtDecode,
|
|
5
|
-
verify as jwtVerify,
|
|
6
|
-
} from 'jsonwebtoken'; // Ensure jsonwebtoken is correctly imported
|
|
7
|
-
import {
|
|
8
|
-
AuthEventType,
|
|
9
|
-
AuthManagerEvent,
|
|
10
|
-
PlatformCheckResponse,
|
|
11
|
-
UserTokenPayload,
|
|
12
|
-
} from './types';
|
|
13
|
-
|
|
14
|
-
export class AuthManager {
|
|
15
|
-
private static instance: AuthManager | null = null;
|
|
16
|
-
|
|
17
|
-
private authServer: string;
|
|
18
|
-
|
|
19
|
-
private realmName: string;
|
|
20
|
-
|
|
21
|
-
private redirectUri: string;
|
|
22
|
-
|
|
23
|
-
private onStateChange: (event: AuthManagerEvent) => void;
|
|
24
|
-
|
|
25
|
-
private constructor(
|
|
26
|
-
authServer: string,
|
|
27
|
-
realmName: string,
|
|
28
|
-
redirectUri: string,
|
|
29
|
-
onStateChange: (event: AuthManagerEvent) => void,
|
|
30
|
-
) {
|
|
31
|
-
this.authServer = authServer;
|
|
32
|
-
this.realmName = realmName;
|
|
33
|
-
this.redirectUri = redirectUri;
|
|
34
|
-
this.onStateChange = onStateChange;
|
|
35
|
-
AuthManager.instance = this;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
public static initialize(
|
|
39
|
-
authServer: string,
|
|
40
|
-
realmName: string,
|
|
41
|
-
redirectUri: string,
|
|
42
|
-
onStateChange: (event: AuthManagerEvent) => void,
|
|
43
|
-
): AuthManager {
|
|
44
|
-
if (!AuthManager.instance) {
|
|
45
|
-
AuthManager.instance = new AuthManager(
|
|
46
|
-
authServer,
|
|
47
|
-
realmName,
|
|
48
|
-
redirectUri,
|
|
49
|
-
onStateChange,
|
|
50
|
-
);
|
|
51
|
-
AuthManager.instance
|
|
52
|
-
.checkAccessToken(true)
|
|
53
|
-
.then((token) => {
|
|
54
|
-
onStateChange({
|
|
55
|
-
type: AuthEventType.INITALIZED_IN,
|
|
56
|
-
user: AuthManager.instance.tokenToPayload(token),
|
|
57
|
-
});
|
|
58
|
-
})
|
|
59
|
-
.catch(() => {
|
|
60
|
-
onStateChange({ type: AuthEventType.INITALIZED_OUT });
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
return AuthManager.instance;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
public static getInstance(): AuthManager {
|
|
67
|
-
if (!AuthManager.instance) {
|
|
68
|
-
throw new Error('AuthManager not initialized');
|
|
69
|
-
}
|
|
70
|
-
return AuthManager.instance;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
private tokenToPayload(token: string): UserTokenPayload {
|
|
74
|
-
return JSON.parse(atob(token.split('.')[1]));
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
private toBase64Url(base64String: string): string {
|
|
78
|
-
return base64String
|
|
79
|
-
.replace(/\+/g, '-')
|
|
80
|
-
.replace(/\//g, '_')
|
|
81
|
-
.replace(/=+$/, '');
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
private generatePKCEPair(): {
|
|
85
|
-
verifier: string,
|
|
86
|
-
challenge: string,
|
|
87
|
-
} {
|
|
88
|
-
const verifier =
|
|
89
|
-
localStorage.getItem('codeVerifier') ??
|
|
90
|
-
this.toBase64Url(randomBytes(32).toString('base64'));
|
|
91
|
-
const challenge =
|
|
92
|
-
localStorage.getItem('codeChallenge') ??
|
|
93
|
-
this.toBase64Url(
|
|
94
|
-
createHash('sha256').update(verifier).digest('base64'),
|
|
95
|
-
);
|
|
96
|
-
|
|
97
|
-
localStorage.setItem('codeVerifier', verifier);
|
|
98
|
-
localStorage.setItem('codeChallenge', challenge);
|
|
99
|
-
|
|
100
|
-
return { verifier, challenge };
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
public async refreshAccessToken(
|
|
104
|
-
isInitialization: boolean = false,
|
|
105
|
-
): Promise<string> {
|
|
106
|
-
try {
|
|
107
|
-
const refreshToken = localStorage.getItem('refresh_token');
|
|
108
|
-
if (!refreshToken) {
|
|
109
|
-
throw new Error('No refresh token found');
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
const response = await axios.post(
|
|
113
|
-
`${this.authServer}auth/refresh`,
|
|
114
|
-
{
|
|
115
|
-
refresh_token: refreshToken,
|
|
116
|
-
},
|
|
117
|
-
);
|
|
118
|
-
this.saveTokens(response, true);
|
|
119
|
-
return response.data.access_token;
|
|
120
|
-
} catch (error) {
|
|
121
|
-
console.error(`Refresh token error, logging out: ${error}`);
|
|
122
|
-
localStorage.removeItem('access_token');
|
|
123
|
-
localStorage.removeItem('refresh_token');
|
|
124
|
-
if (!isInitialization) {
|
|
125
|
-
// throw refresh fail only if not initialization
|
|
126
|
-
this.onStateChange({ type: AuthEventType.REFRESH_FAILED });
|
|
127
|
-
}
|
|
128
|
-
throw error;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
public async checkAccessToken(
|
|
133
|
-
isInitilization: boolean = false,
|
|
134
|
-
): Promise<string> {
|
|
135
|
-
const accessToken = localStorage.getItem('access_token');
|
|
136
|
-
if (accessToken && this.isTokenExpired(accessToken)) {
|
|
137
|
-
return this.refreshAccessToken(isInitilization);
|
|
138
|
-
}
|
|
139
|
-
return accessToken;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
private isTokenExpired(token: string): boolean {
|
|
143
|
-
const decoded = this.tokenToPayload(token);
|
|
144
|
-
return decoded.exp < Date.now() / 1000;
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
public async mustBeLoggedIn(): Promise<void> {
|
|
148
|
-
if (!(await this.isLoggedIn())) {
|
|
149
|
-
this.onStateChange({
|
|
150
|
-
type: AuthEventType.FAILED_MUST_LOGIN_CHECK,
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
public getLoginWithGoogleUri(): string {
|
|
156
|
-
const { challenge } = this.generatePKCEPair();
|
|
157
|
-
return `${this.authServer}auth/login_with_google?realm_name=${this.realmName}&redirect_uri=${encodeURIComponent(this.redirectUri)}&code_challenge=${challenge}&code_challenge_method=S256`;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
public async isLoggedIn(): Promise<boolean> {
|
|
161
|
-
const accessToken = localStorage.getItem('access_token');
|
|
162
|
-
const refreshToken = localStorage.getItem('refresh_token');
|
|
163
|
-
|
|
164
|
-
// If either token is missing, user is not logged in
|
|
165
|
-
if (!accessToken || !refreshToken) {
|
|
166
|
-
return false;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// If access token is expired, try to refresh
|
|
170
|
-
if (this.isTokenExpired(accessToken)) {
|
|
171
|
-
try {
|
|
172
|
-
await this.refreshAccessToken();
|
|
173
|
-
return true;
|
|
174
|
-
} catch {
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
// If access token is valid
|
|
180
|
-
return true;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
public async getAccessToken(
|
|
184
|
-
mustBeLoggedIn: boolean = false,
|
|
185
|
-
): Promise<string> {
|
|
186
|
-
try {
|
|
187
|
-
return await this.checkAccessToken();
|
|
188
|
-
} catch (error) {
|
|
189
|
-
if (mustBeLoggedIn) {
|
|
190
|
-
this.onStateChange({
|
|
191
|
-
type: AuthEventType.FAILED_MUST_LOGIN_CHECK,
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
return '';
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
public async platformCheck(
|
|
199
|
-
email: string,
|
|
200
|
-
): Promise<PlatformCheckResponse> {
|
|
201
|
-
const response = await axios.post(
|
|
202
|
-
`${this.authServer}auth/email/platform_check`,
|
|
203
|
-
{
|
|
204
|
-
realm_name: this.realmName,
|
|
205
|
-
email,
|
|
206
|
-
},
|
|
207
|
-
);
|
|
208
|
-
if (response.data.error || response.data.errors) {
|
|
209
|
-
throw new Error(response.data.error || response.data.message);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
return response.status === 200
|
|
213
|
-
? response.data
|
|
214
|
-
: { platforms: [] };
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
public async verifyEmail(
|
|
218
|
-
email: string,
|
|
219
|
-
token: string,
|
|
220
|
-
): Promise<boolean> {
|
|
221
|
-
const response = await axios.post(
|
|
222
|
-
`${this.authServer}auth/email/verify`,
|
|
223
|
-
{
|
|
224
|
-
realm_name: this.realmName,
|
|
225
|
-
email,
|
|
226
|
-
token,
|
|
227
|
-
},
|
|
228
|
-
);
|
|
229
|
-
if (response.data.error || response.data.errors) {
|
|
230
|
-
throw new Error(response.data.error || response.data.message);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return response.status === 200;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
public async doPassReset(
|
|
237
|
-
email: string,
|
|
238
|
-
token: string,
|
|
239
|
-
newPassword: string,
|
|
240
|
-
): Promise<boolean> {
|
|
241
|
-
const response = await axios.post(
|
|
242
|
-
`${this.authServer}auth/email/do_pass_reset`,
|
|
243
|
-
{
|
|
244
|
-
realm_name: this.realmName,
|
|
245
|
-
email,
|
|
246
|
-
token,
|
|
247
|
-
new_password: newPassword,
|
|
248
|
-
},
|
|
249
|
-
);
|
|
250
|
-
if (response.data.error || response.data.errors) {
|
|
251
|
-
throw new Error(response.data.error || response.data.message);
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
return response.status === 200;
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
public async changeEmail(email: string): Promise<boolean> {
|
|
258
|
-
const accessToken = localStorage.getItem('access_token');
|
|
259
|
-
if (!accessToken) {
|
|
260
|
-
throw new Error('Access token not found');
|
|
261
|
-
}
|
|
262
|
-
const response = await axios.post(
|
|
263
|
-
`${this.authServer}auth/email/change_email`,
|
|
264
|
-
{
|
|
265
|
-
realm_name: this.realmName,
|
|
266
|
-
email,
|
|
267
|
-
},
|
|
268
|
-
{
|
|
269
|
-
headers: { Authorization: `Bearer ${accessToken}` },
|
|
270
|
-
},
|
|
271
|
-
);
|
|
272
|
-
if (response.data.error || response.data.errors) {
|
|
273
|
-
throw new Error(response.data.error || response.data.message);
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
return response.status === 200;
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
public async initPasswordReset(email: string): Promise<boolean> {
|
|
280
|
-
const response = await axios.post(
|
|
281
|
-
`${this.authServer}auth/email/init_pass_reset`,
|
|
282
|
-
{
|
|
283
|
-
realm_name: this.realmName,
|
|
284
|
-
email,
|
|
285
|
-
},
|
|
286
|
-
);
|
|
287
|
-
if (response.data.error || response.data.errors) {
|
|
288
|
-
throw new Error(response.data.error || response.data.message);
|
|
289
|
-
}
|
|
290
|
-
|
|
291
|
-
return response.status === 200 || response.status === 201;
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
/**
|
|
295
|
-
* Updates user account fields. Only sends fields present in the update object.
|
|
296
|
-
* For password, expects: { old: string, new: string }
|
|
297
|
-
*/
|
|
298
|
-
public async updateAccount(update: {
|
|
299
|
-
firstName?: string,
|
|
300
|
-
lastName?: string,
|
|
301
|
-
email?: string,
|
|
302
|
-
password?: { old: string, new: string, },
|
|
303
|
-
}): Promise<boolean> {
|
|
304
|
-
const accessToken = localStorage.getItem('access_token');
|
|
305
|
-
if (!accessToken) {
|
|
306
|
-
throw new Error('Access token not found');
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
// Update name
|
|
310
|
-
if (update.firstName || update.lastName) {
|
|
311
|
-
const response = await axios.post(
|
|
312
|
-
`${this.authServer}auth/email/update_profile`,
|
|
313
|
-
{
|
|
314
|
-
realm_name: this.realmName,
|
|
315
|
-
...(update.firstName && { first_name: update.firstName }),
|
|
316
|
-
...(update.lastName && { last_name: update.lastName }),
|
|
317
|
-
},
|
|
318
|
-
{
|
|
319
|
-
headers: { Authorization: `Bearer ${accessToken}` },
|
|
320
|
-
},
|
|
321
|
-
);
|
|
322
|
-
if (response.data.error || response.data.errors) {
|
|
323
|
-
throw new Error(response.data.error || response.data.message);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
// Update email
|
|
328
|
-
if (update.email) {
|
|
329
|
-
const response = await axios.post(
|
|
330
|
-
`${this.authServer}auth/email/change_email`,
|
|
331
|
-
{
|
|
332
|
-
realm_name: this.realmName,
|
|
333
|
-
email: update.email,
|
|
334
|
-
},
|
|
335
|
-
{
|
|
336
|
-
headers: { Authorization: `Bearer ${accessToken}` },
|
|
337
|
-
},
|
|
338
|
-
);
|
|
339
|
-
if (response.data.error || response.data.errors) {
|
|
340
|
-
throw new Error(response.data.error || response.data.message);
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
// Update password
|
|
345
|
-
if (update.password && update.email) {
|
|
346
|
-
const response = await axios.post(
|
|
347
|
-
`${this.authServer}auth/email/change_pass`,
|
|
348
|
-
{
|
|
349
|
-
realm_name: this.realmName,
|
|
350
|
-
email: update.email,
|
|
351
|
-
old_password: update.password.old,
|
|
352
|
-
new_password: update.password.new,
|
|
353
|
-
},
|
|
354
|
-
{
|
|
355
|
-
headers: { Authorization: `Bearer ${accessToken}` },
|
|
356
|
-
},
|
|
357
|
-
);
|
|
358
|
-
if (response.data.error || response.data.errors) {
|
|
359
|
-
throw new Error(response.data.error || response.data.message);
|
|
360
|
-
}
|
|
361
|
-
} else if (update.password && !update.email) {
|
|
362
|
-
throw new Error('Email is required to change password');
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
return true;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
public async changePassword(
|
|
369
|
-
oldPassword: string,
|
|
370
|
-
newPassword: string,
|
|
371
|
-
email: string,
|
|
372
|
-
): Promise<boolean> {
|
|
373
|
-
const accessToken = localStorage.getItem('access_token');
|
|
374
|
-
if (!accessToken) {
|
|
375
|
-
throw new Error('Access token not found');
|
|
376
|
-
}
|
|
377
|
-
const response = await axios.post(
|
|
378
|
-
`${this.authServer}auth/email/change_pass`,
|
|
379
|
-
{
|
|
380
|
-
realm_name: this.realmName,
|
|
381
|
-
email,
|
|
382
|
-
old_password: oldPassword,
|
|
383
|
-
new_password: newPassword,
|
|
384
|
-
},
|
|
385
|
-
{
|
|
386
|
-
headers: { Authorization: `Bearer ${accessToken}` },
|
|
387
|
-
},
|
|
388
|
-
);
|
|
389
|
-
if (response.data.error || response.data.errors) {
|
|
390
|
-
throw new Error(response.data.error || response.data.message);
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
return response.status === 200;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
public async registerUsingEmail(
|
|
397
|
-
firstName: string,
|
|
398
|
-
lastName: string,
|
|
399
|
-
email: string,
|
|
400
|
-
password: string,
|
|
401
|
-
): Promise<void> {
|
|
402
|
-
const response = await axios.post(
|
|
403
|
-
`${this.authServer}auth/email/register`,
|
|
404
|
-
{
|
|
405
|
-
realm_name: this.realmName,
|
|
406
|
-
first_name: firstName,
|
|
407
|
-
last_name: lastName,
|
|
408
|
-
email,
|
|
409
|
-
password,
|
|
410
|
-
},
|
|
411
|
-
);
|
|
412
|
-
if (response.data.message || response.data.error) {
|
|
413
|
-
throw new Error(response.data.message || response.data.error);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
if (!response.data.access_token) {
|
|
417
|
-
throw new Error('Something went wrong');
|
|
418
|
-
}
|
|
419
|
-
|
|
420
|
-
this.saveTokens(response, false);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
private saveTokens(
|
|
424
|
-
response: AxiosResponse,
|
|
425
|
-
byRefresh: boolean,
|
|
426
|
-
): void {
|
|
427
|
-
localStorage.setItem('access_token', response.data.access_token);
|
|
428
|
-
localStorage.setItem(
|
|
429
|
-
'refresh_token',
|
|
430
|
-
response.data.refresh_token,
|
|
431
|
-
);
|
|
432
|
-
this.onStateChange({
|
|
433
|
-
type: byRefresh
|
|
434
|
-
? AuthEventType.USER_UPDATED
|
|
435
|
-
: AuthEventType.USER_LOGGED_IN,
|
|
436
|
-
user: this.tokenToPayload(response.data.access_token),
|
|
437
|
-
});
|
|
438
|
-
const user = this.tokenToPayload(response.data.access_token);
|
|
439
|
-
localStorage.setItem('user', JSON.stringify(user));
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
public async loginUsingEmail(
|
|
443
|
-
email: string,
|
|
444
|
-
password: string,
|
|
445
|
-
): Promise<void> {
|
|
446
|
-
const response = await axios.post(
|
|
447
|
-
`${this.authServer}auth/email/login`,
|
|
448
|
-
{
|
|
449
|
-
realm_name: this.realmName,
|
|
450
|
-
email,
|
|
451
|
-
password,
|
|
452
|
-
},
|
|
453
|
-
);
|
|
454
|
-
if (response.data.message || response.data.error) {
|
|
455
|
-
throw new Error(response.data.message || response.data.error);
|
|
456
|
-
}
|
|
457
|
-
this.saveTokens(response, false);
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
public async loginUsingPkce(code: string): Promise<void> {
|
|
461
|
-
try {
|
|
462
|
-
const codeVerifier = localStorage.getItem('codeVerifier');
|
|
463
|
-
if (!codeVerifier) {
|
|
464
|
-
throw new Error('Code verifier not found');
|
|
465
|
-
}
|
|
466
|
-
|
|
467
|
-
const response = await axios.post(
|
|
468
|
-
`${this.authServer}auth/pkce_exchange`,
|
|
469
|
-
{
|
|
470
|
-
realm_name: this.realmName,
|
|
471
|
-
code,
|
|
472
|
-
redirect_uri: this.redirectUri,
|
|
473
|
-
code_verifier: codeVerifier,
|
|
474
|
-
},
|
|
475
|
-
);
|
|
476
|
-
this.saveTokens(response, false);
|
|
477
|
-
} finally {
|
|
478
|
-
localStorage.removeItem('codeVerifier');
|
|
479
|
-
localStorage.removeItem('codeChallenge');
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
|
|
483
|
-
public async logout(): Promise<void> {
|
|
484
|
-
try {
|
|
485
|
-
const accessToken = localStorage.getItem('access_token');
|
|
486
|
-
if (!accessToken) {
|
|
487
|
-
throw new Error('Access token not found');
|
|
488
|
-
}
|
|
489
|
-
await axios.post(
|
|
490
|
-
`${this.authServer}auth/logout`,
|
|
491
|
-
{},
|
|
492
|
-
{
|
|
493
|
-
headers: { Authorization: `Bearer ${accessToken}` },
|
|
494
|
-
},
|
|
495
|
-
);
|
|
496
|
-
} finally {
|
|
497
|
-
localStorage.removeItem('access_token');
|
|
498
|
-
localStorage.removeItem('refresh_token');
|
|
499
|
-
this.onStateChange({ type: AuthEventType.USER_LOGGED_OUT });
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
public static async validateToken(
|
|
504
|
-
authServer: string,
|
|
505
|
-
bearerToken: string,
|
|
506
|
-
): Promise<UserTokenPayload> {
|
|
507
|
-
// @todo tests missing for this static validation
|
|
508
|
-
// @todo add caching for public key and algo
|
|
509
|
-
const decodedToken = jwtDecode(bearerToken, {
|
|
510
|
-
complete: true,
|
|
511
|
-
})?.payload as unknown as UserTokenPayload;
|
|
512
|
-
|
|
513
|
-
if (!decodedToken) {
|
|
514
|
-
throw new Error('Not a valid jwt token');
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
const userToken: UserTokenPayload = {
|
|
518
|
-
id: decodedToken.id,
|
|
519
|
-
iss: decodedToken.iss,
|
|
520
|
-
sub:
|
|
521
|
-
typeof decodedToken.sub === 'string'
|
|
522
|
-
? parseInt(decodedToken.sub)
|
|
523
|
-
: decodedToken.sub,
|
|
524
|
-
first_name: decodedToken.first_name,
|
|
525
|
-
last_name: decodedToken.last_name,
|
|
526
|
-
email: decodedToken.email,
|
|
527
|
-
aud: decodedToken.aud,
|
|
528
|
-
iat: decodedToken.iat,
|
|
529
|
-
exp: decodedToken.exp,
|
|
530
|
-
scopes: decodedToken.scopes,
|
|
531
|
-
realm: decodedToken.realm,
|
|
532
|
-
provider: decodedToken.provider,
|
|
533
|
-
};
|
|
534
|
-
|
|
535
|
-
const { data: publicKey } = await axios.get(
|
|
536
|
-
`${authServer}public/public_key`,
|
|
537
|
-
);
|
|
538
|
-
const { data: algo } = await axios.get(
|
|
539
|
-
`${authServer}public/algo`,
|
|
540
|
-
);
|
|
541
|
-
|
|
542
|
-
jwtVerify(bearerToken, publicKey, { algorithms: [algo] });
|
|
543
|
-
|
|
544
|
-
const { data: revokedIds } = await axios.get(
|
|
545
|
-
`${authServer}public/revoked_ids`,
|
|
546
|
-
);
|
|
547
|
-
if (revokedIds.includes(decodedToken.id)) {
|
|
548
|
-
throw new Error('Token is revoked');
|
|
549
|
-
}
|
|
550
|
-
return userToken;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
public static resetInstance(): void {
|
|
554
|
-
AuthManager.instance = null;
|
|
555
|
-
}
|
|
556
|
-
}
|
package/src/index.ts
DELETED
package/src/types.ts
DELETED
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
export enum AuthEventType {
|
|
3
|
-
INITALIZED_IN = 'initialized-logged-in',
|
|
4
|
-
INITALIZED_OUT = 'initialized-logged-out',
|
|
5
|
-
USER_LOGGED_IN = 'user-logged-in',
|
|
6
|
-
USER_LOGGED_OUT = 'user-logged-out',
|
|
7
|
-
USER_UPDATED = 'user-updated',
|
|
8
|
-
FAILED_MUST_LOGIN_CHECK = 'failed-must-login',
|
|
9
|
-
REFRESH_FAILED = 'refresh-failed',
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface UserTokenPayload {
|
|
13
|
-
id: number;
|
|
14
|
-
iss: string;
|
|
15
|
-
sub: number | string;
|
|
16
|
-
first_name: string;
|
|
17
|
-
last_name: string;
|
|
18
|
-
email: string;
|
|
19
|
-
aud: string;
|
|
20
|
-
iat: number;
|
|
21
|
-
exp: number;
|
|
22
|
-
scopes: string;
|
|
23
|
-
realm: string;
|
|
24
|
-
provider: Platforms;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export interface AuthManagerEvent {
|
|
28
|
-
type: AuthEventType;
|
|
29
|
-
user?: UserTokenPayload;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
export interface PlatformCheckResponse {
|
|
33
|
-
platforms: Platforms[];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export enum Platforms {
|
|
37
|
-
PASSWORD = 'password',
|
|
38
|
-
GOOGLE = 'google',
|
|
39
|
-
FACEBOOK = 'facebook',
|
|
40
|
-
TWITTER = 'twitter',
|
|
41
|
-
GITHUB = 'github',
|
|
42
|
-
APPLE = 'apple',
|
|
43
|
-
LINKEDIN = 'linkedin',
|
|
44
|
-
MICROSOFT = 'microsoft',
|
|
45
|
-
}
|