supaapps-auth 2.0.0-rc.8 → 2.0.0

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, UserTokenPayload } from './types';
1
+ import { AuthManagerEvent, PlatformCheckResponse, UserTokenPayload } from './types';
2
2
  export declare class AuthManager {
3
3
  private static instance;
4
4
  private authServer;
@@ -18,10 +18,24 @@ export declare class AuthManager {
18
18
  getLoginWithGoogleUri(): string;
19
19
  isLoggedIn(): Promise<boolean>;
20
20
  getAccessToken(mustBeLoggedIn?: boolean): Promise<string>;
21
+ platformCheck(email: string): Promise<PlatformCheckResponse>;
21
22
  verifyEmail(email: string, token: string): Promise<boolean>;
22
23
  doPassReset(email: string, token: string, newPassword: string): Promise<boolean>;
23
24
  changeEmail(email: string): Promise<boolean>;
24
25
  initPasswordReset(email: string): Promise<boolean>;
26
+ /**
27
+ * Updates user account fields. Only sends fields present in the update object.
28
+ * For password, expects: { old: string, new: string }
29
+ */
30
+ updateAccount(update: {
31
+ firstName?: string;
32
+ lastName?: string;
33
+ email?: string;
34
+ password?: {
35
+ old: string;
36
+ new: string;
37
+ };
38
+ }): Promise<boolean>;
25
39
  changePassword(oldPassword: string, newPassword: string, email: string): Promise<boolean>;
26
40
  registerUsingEmail(firstName: string, lastName: string, email: string, password: string): Promise<void>;
27
41
  private saveTokens;
@@ -139,6 +139,20 @@ class AuthManager {
139
139
  }
140
140
  });
141
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
152
+ ? response.data
153
+ : { platforms: [] };
154
+ });
155
+ }
142
156
  verifyEmail(email, token) {
143
157
  return __awaiter(this, void 0, void 0, function* () {
144
158
  const response = yield axios_1.default.post(`${this.authServer}auth/email/verify`, {
@@ -196,6 +210,57 @@ class AuthManager {
196
210
  return response.status === 200 || response.status === 201;
197
211
  });
198
212
  }
213
+ /**
214
+ * Updates user account fields. Only sends fields present in the update object.
215
+ * For password, expects: { old: string, new: string }
216
+ */
217
+ updateAccount(update) {
218
+ return __awaiter(this, void 0, void 0, function* () {
219
+ const accessToken = localStorage.getItem('access_token');
220
+ if (!accessToken) {
221
+ throw new Error('Access token not found');
222
+ }
223
+ // Update name
224
+ if (update.firstName || update.lastName) {
225
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/update_profile`, Object.assign(Object.assign({ realm_name: this.realmName }, (update.firstName && { first_name: update.firstName })), (update.lastName && { last_name: update.lastName })), {
226
+ headers: { Authorization: `Bearer ${accessToken}` },
227
+ });
228
+ if (response.data.error || response.data.errors) {
229
+ throw new Error(response.data.error || response.data.message);
230
+ }
231
+ }
232
+ // Update email
233
+ if (update.email) {
234
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/change_email`, {
235
+ realm_name: this.realmName,
236
+ email: update.email,
237
+ }, {
238
+ headers: { Authorization: `Bearer ${accessToken}` },
239
+ });
240
+ if (response.data.error || response.data.errors) {
241
+ throw new Error(response.data.error || response.data.message);
242
+ }
243
+ }
244
+ // Update password
245
+ if (update.password && update.email) {
246
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/change_pass`, {
247
+ realm_name: this.realmName,
248
+ email: update.email,
249
+ old_password: update.password.old,
250
+ new_password: update.password.new,
251
+ }, {
252
+ headers: { Authorization: `Bearer ${accessToken}` },
253
+ });
254
+ if (response.data.error || response.data.errors) {
255
+ throw new Error(response.data.error || response.data.message);
256
+ }
257
+ }
258
+ else if (update.password && !update.email) {
259
+ throw new Error('Email is required to change password');
260
+ }
261
+ return true;
262
+ });
263
+ }
199
264
  changePassword(oldPassword, newPassword, email) {
200
265
  return __awaiter(this, void 0, void 0, function* () {
201
266
  const accessToken = localStorage.getItem('access_token');
@@ -238,7 +303,9 @@ class AuthManager {
238
303
  localStorage.setItem('access_token', response.data.access_token);
239
304
  localStorage.setItem('refresh_token', response.data.refresh_token);
240
305
  this.onStateChange({
241
- type: byRefresh ? types_1.AuthEventType.USER_UPDATED : types_1.AuthEventType.USER_LOGGED_IN,
306
+ type: byRefresh
307
+ ? types_1.AuthEventType.USER_UPDATED
308
+ : types_1.AuthEventType.USER_LOGGED_IN,
242
309
  user: this.tokenToPayload(response.data.access_token),
243
310
  });
244
311
  const user = this.tokenToPayload(response.data.access_token);
@@ -310,7 +377,9 @@ class AuthManager {
310
377
  const userToken = {
311
378
  id: decodedToken.id,
312
379
  iss: decodedToken.iss,
313
- sub: typeof decodedToken.sub === 'string' ? parseInt(decodedToken.sub) : decodedToken.sub,
380
+ sub: typeof decodedToken.sub === 'string'
381
+ ? parseInt(decodedToken.sub)
382
+ : decodedToken.sub,
314
383
  first_name: decodedToken.first_name,
315
384
  last_name: decodedToken.last_name,
316
385
  email: decodedToken.email,
@@ -319,6 +388,7 @@ class AuthManager {
319
388
  exp: decodedToken.exp,
320
389
  scopes: decodedToken.scopes,
321
390
  realm: decodedToken.realm,
391
+ provider: decodedToken.provider,
322
392
  };
323
393
  const { data: publicKey } = yield axios_1.default.get(`${authServer}public/public_key`);
324
394
  const { data: algo } = yield axios_1.default.get(`${authServer}public/algo`);
package/dist/types.d.ts CHANGED
@@ -19,8 +19,22 @@ export interface UserTokenPayload {
19
19
  exp: number;
20
20
  scopes: string;
21
21
  realm: string;
22
+ provider: Platforms;
22
23
  }
23
24
  export interface AuthManagerEvent {
24
25
  type: AuthEventType;
25
26
  user?: UserTokenPayload;
26
27
  }
28
+ export interface PlatformCheckResponse {
29
+ platform: Platforms[];
30
+ }
31
+ export declare 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
+ }
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.8",
3
+ "version": "2.0.0",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -4,7 +4,12 @@ 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 {
8
+ AuthEventType,
9
+ AuthManagerEvent,
10
+ PlatformCheckResponse,
11
+ UserTokenPayload,
12
+ } from './types';
8
13
 
9
14
  export class AuthManager {
10
15
  private static instance: AuthManager | null = null;
@@ -44,16 +49,16 @@ export class AuthManager {
44
49
  onStateChange,
45
50
  );
46
51
  AuthManager.instance
47
- .checkAccessToken(true)
48
- .then((token) => {
49
- onStateChange({
50
- type: AuthEventType.INITALIZED_IN,
51
- user: AuthManager.instance.tokenToPayload(token),
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 });
52
61
  });
53
- })
54
- .catch(() => {
55
- onStateChange({ type: AuthEventType.INITALIZED_OUT });
56
- });
57
62
  }
58
63
  return AuthManager.instance;
59
64
  }
@@ -95,7 +100,9 @@ export class AuthManager {
95
100
  return { verifier, challenge };
96
101
  }
97
102
 
98
- public async refreshAccessToken(isInitialization: boolean = false): Promise<string> {
103
+ public async refreshAccessToken(
104
+ isInitialization: boolean = false,
105
+ ): Promise<string> {
99
106
  try {
100
107
  const refreshToken = localStorage.getItem('refresh_token');
101
108
  if (!refreshToken) {
@@ -122,7 +129,9 @@ export class AuthManager {
122
129
  }
123
130
  }
124
131
 
125
- public async checkAccessToken(isInitilization: boolean = false): Promise<string> {
132
+ public async checkAccessToken(
133
+ isInitilization: boolean = false,
134
+ ): Promise<string> {
126
135
  const accessToken = localStorage.getItem('access_token');
127
136
  if (accessToken && this.isTokenExpired(accessToken)) {
128
137
  return this.refreshAccessToken(isInitilization);
@@ -157,7 +166,9 @@ export class AuthManager {
157
166
  }
158
167
  }
159
168
 
160
- public async getAccessToken(mustBeLoggedIn: boolean = false): Promise<string> {
169
+ public async getAccessToken(
170
+ mustBeLoggedIn: boolean = false,
171
+ ): Promise<string> {
161
172
  try {
162
173
  return await this.checkAccessToken();
163
174
  } catch (error) {
@@ -170,7 +181,29 @@ export class AuthManager {
170
181
  }
171
182
  }
172
183
 
173
- public async verifyEmail(email: string, token: string): Promise<boolean> {
184
+ public async platformCheck(
185
+ email: string,
186
+ ): Promise<PlatformCheckResponse> {
187
+ const response = await axios.post(
188
+ `${this.authServer}auth/email/platform_check`,
189
+ {
190
+ realm_name: this.realmName,
191
+ email,
192
+ },
193
+ );
194
+ if (response.data.error || response.data.errors) {
195
+ throw new Error(response.data.error || response.data.message);
196
+ }
197
+
198
+ return response.status === 200
199
+ ? response.data
200
+ : { platforms: [] };
201
+ }
202
+
203
+ public async verifyEmail(
204
+ email: string,
205
+ token: string,
206
+ ): Promise<boolean> {
174
207
  const response = await axios.post(
175
208
  `${this.authServer}auth/email/verify`,
176
209
  {
@@ -186,15 +219,19 @@ export class AuthManager {
186
219
  return response.status === 200;
187
220
  }
188
221
 
189
- public async doPassReset(email: string, token: string, newPassword: string): Promise<boolean> {
222
+ public async doPassReset(
223
+ email: string,
224
+ token: string,
225
+ newPassword: string,
226
+ ): Promise<boolean> {
190
227
  const response = await axios.post(
191
- `${this.authServer}auth/email/do_pass_reset`,
192
- {
193
- realm_name: this.realmName,
194
- email,
195
- token,
196
- new_password: newPassword,
197
- },
228
+ `${this.authServer}auth/email/do_pass_reset`,
229
+ {
230
+ realm_name: this.realmName,
231
+ email,
232
+ token,
233
+ new_password: newPassword,
234
+ },
198
235
  );
199
236
  if (response.data.error || response.data.errors) {
200
237
  throw new Error(response.data.error || response.data.message);
@@ -240,7 +277,85 @@ export class AuthManager {
240
277
  return response.status === 200 || response.status === 201;
241
278
  }
242
279
 
243
- public async changePassword(oldPassword: string, newPassword: string, email: string): Promise<boolean> {
280
+ /**
281
+ * Updates user account fields. Only sends fields present in the update object.
282
+ * For password, expects: { old: string, new: string }
283
+ */
284
+ public async updateAccount(update: {
285
+ firstName?: string,
286
+ lastName?: string,
287
+ email?: string,
288
+ password?: { old: string, new: string, },
289
+ }): Promise<boolean> {
290
+ const accessToken = localStorage.getItem('access_token');
291
+ if (!accessToken) {
292
+ throw new Error('Access token not found');
293
+ }
294
+
295
+ // Update name
296
+ if (update.firstName || update.lastName) {
297
+ const response = await axios.post(
298
+ `${this.authServer}auth/email/update_profile`,
299
+ {
300
+ realm_name: this.realmName,
301
+ ...(update.firstName && { first_name: update.firstName }),
302
+ ...(update.lastName && { last_name: update.lastName }),
303
+ },
304
+ {
305
+ headers: { Authorization: `Bearer ${accessToken}` },
306
+ },
307
+ );
308
+ if (response.data.error || response.data.errors) {
309
+ throw new Error(response.data.error || response.data.message);
310
+ }
311
+ }
312
+
313
+ // Update email
314
+ if (update.email) {
315
+ const response = await axios.post(
316
+ `${this.authServer}auth/email/change_email`,
317
+ {
318
+ realm_name: this.realmName,
319
+ email: update.email,
320
+ },
321
+ {
322
+ headers: { Authorization: `Bearer ${accessToken}` },
323
+ },
324
+ );
325
+ if (response.data.error || response.data.errors) {
326
+ throw new Error(response.data.error || response.data.message);
327
+ }
328
+ }
329
+
330
+ // Update password
331
+ if (update.password && update.email) {
332
+ const response = await axios.post(
333
+ `${this.authServer}auth/email/change_pass`,
334
+ {
335
+ realm_name: this.realmName,
336
+ email: update.email,
337
+ old_password: update.password.old,
338
+ new_password: update.password.new,
339
+ },
340
+ {
341
+ headers: { Authorization: `Bearer ${accessToken}` },
342
+ },
343
+ );
344
+ if (response.data.error || response.data.errors) {
345
+ throw new Error(response.data.error || response.data.message);
346
+ }
347
+ } else if (update.password && !update.email) {
348
+ throw new Error('Email is required to change password');
349
+ }
350
+
351
+ return true;
352
+ }
353
+
354
+ public async changePassword(
355
+ oldPassword: string,
356
+ newPassword: string,
357
+ email: string,
358
+ ): Promise<boolean> {
244
359
  const accessToken = localStorage.getItem('access_token');
245
360
  if (!accessToken) {
246
361
  throw new Error('Access token not found');
@@ -265,10 +380,10 @@ export class AuthManager {
265
380
  }
266
381
 
267
382
  public async registerUsingEmail(
268
- firstName: string,
269
- lastName: string,
270
- email: string,
271
- password: string
383
+ firstName: string,
384
+ lastName: string,
385
+ email: string,
386
+ password: string,
272
387
  ): Promise<void> {
273
388
  const response = await axios.post(
274
389
  `${this.authServer}auth/email/register`,
@@ -285,27 +400,35 @@ export class AuthManager {
285
400
  }
286
401
 
287
402
  if (!response.data.access_token) {
288
- throw new Error('Something went wrong');
403
+ throw new Error('Something went wrong');
289
404
  }
290
405
 
291
406
  this.saveTokens(response, false);
292
407
  }
293
408
 
294
- private saveTokens(response: AxiosResponse, byRefresh: boolean): void {
409
+ private saveTokens(
410
+ response: AxiosResponse,
411
+ byRefresh: boolean,
412
+ ): void {
295
413
  localStorage.setItem('access_token', response.data.access_token);
296
414
  localStorage.setItem(
297
415
  'refresh_token',
298
416
  response.data.refresh_token,
299
417
  );
300
418
  this.onStateChange({
301
- type: byRefresh ? AuthEventType.USER_UPDATED : AuthEventType.USER_LOGGED_IN,
419
+ type: byRefresh
420
+ ? AuthEventType.USER_UPDATED
421
+ : AuthEventType.USER_LOGGED_IN,
302
422
  user: this.tokenToPayload(response.data.access_token),
303
- });
423
+ });
304
424
  const user = this.tokenToPayload(response.data.access_token);
305
425
  localStorage.setItem('user', JSON.stringify(user));
306
426
  }
307
427
 
308
- public async loginUsingEmail(email: string, password: string): Promise<void> {
428
+ public async loginUsingEmail(
429
+ email: string,
430
+ password: string,
431
+ ): Promise<void> {
309
432
  const response = await axios.post(
310
433
  `${this.authServer}auth/email/login`,
311
434
  {
@@ -378,18 +501,22 @@ export class AuthManager {
378
501
  }
379
502
 
380
503
  const userToken: UserTokenPayload = {
381
- id: decodedToken.id,
382
- iss: decodedToken.iss,
383
- sub: typeof decodedToken.sub === 'string' ? parseInt(decodedToken.sub) : decodedToken.sub,
384
- first_name: decodedToken.first_name,
385
- last_name: decodedToken.last_name,
386
- email: decodedToken.email,
387
- aud: decodedToken.aud,
388
- iat: decodedToken.iat,
389
- exp: decodedToken.exp,
390
- scopes: decodedToken.scopes,
391
- realm: decodedToken.realm,
392
- }
504
+ id: decodedToken.id,
505
+ iss: decodedToken.iss,
506
+ sub:
507
+ typeof decodedToken.sub === 'string'
508
+ ? parseInt(decodedToken.sub)
509
+ : decodedToken.sub,
510
+ first_name: decodedToken.first_name,
511
+ last_name: decodedToken.last_name,
512
+ email: decodedToken.email,
513
+ aud: decodedToken.aud,
514
+ iat: decodedToken.iat,
515
+ exp: decodedToken.exp,
516
+ scopes: decodedToken.scopes,
517
+ realm: decodedToken.realm,
518
+ provider: decodedToken.provider,
519
+ };
393
520
 
394
521
  const { data: publicKey } = await axios.get(
395
522
  `${authServer}public/public_key`,
@@ -403,7 +530,7 @@ export class AuthManager {
403
530
  const { data: revokedIds } = await axios.get(
404
531
  `${authServer}public/revoked_ids`,
405
532
  );
406
- if(revokedIds.includes(decodedToken.id)){
533
+ if (revokedIds.includes(decodedToken.id)) {
407
534
  throw new Error('Token is revoked');
408
535
  }
409
536
  return userToken;
package/src/types.ts CHANGED
@@ -21,9 +21,25 @@ export interface UserTokenPayload {
21
21
  exp: number;
22
22
  scopes: string;
23
23
  realm: string;
24
+ provider: Platforms;
24
25
  }
25
26
 
26
27
  export interface AuthManagerEvent {
27
28
  type: AuthEventType;
28
29
  user?: UserTokenPayload;
29
30
  }
31
+
32
+ export interface PlatformCheckResponse {
33
+ platform: 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
+ }