supaapps-auth 2.0.0-rc.9 → 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,11 +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, token: string): Promise<boolean>;
21
+ platformCheck(email: string): Promise<PlatformCheckResponse>;
22
22
  verifyEmail(email: string, token: string): Promise<boolean>;
23
23
  doPassReset(email: string, token: string, newPassword: string): Promise<boolean>;
24
24
  changeEmail(email: string): Promise<boolean>;
25
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>;
26
39
  changePassword(oldPassword: string, newPassword: string, email: string): Promise<boolean>;
27
40
  registerUsingEmail(firstName: string, lastName: string, email: string, password: string): Promise<void>;
28
41
  private saveTokens;
@@ -139,7 +139,7 @@ class AuthManager {
139
139
  }
140
140
  });
141
141
  }
142
- platformCheck(email, token) {
142
+ platformCheck(email) {
143
143
  return __awaiter(this, void 0, void 0, function* () {
144
144
  const response = yield axios_1.default.post(`${this.authServer}auth/email/platform_check`, {
145
145
  realm_name: this.realmName,
@@ -148,7 +148,9 @@ class AuthManager {
148
148
  if (response.data.error || response.data.errors) {
149
149
  throw new Error(response.data.error || response.data.message);
150
150
  }
151
- return (response.status === 200) ? response.data : { 'platforms': [] };
151
+ return response.status === 200
152
+ ? response.data
153
+ : { platforms: [] };
152
154
  });
153
155
  }
154
156
  verifyEmail(email, token) {
@@ -208,6 +210,57 @@ class AuthManager {
208
210
  return response.status === 200 || response.status === 201;
209
211
  });
210
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
+ }
211
264
  changePassword(oldPassword, newPassword, email) {
212
265
  return __awaiter(this, void 0, void 0, function* () {
213
266
  const accessToken = localStorage.getItem('access_token');
@@ -250,7 +303,9 @@ class AuthManager {
250
303
  localStorage.setItem('access_token', response.data.access_token);
251
304
  localStorage.setItem('refresh_token', response.data.refresh_token);
252
305
  this.onStateChange({
253
- 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,
254
309
  user: this.tokenToPayload(response.data.access_token),
255
310
  });
256
311
  const user = this.tokenToPayload(response.data.access_token);
@@ -322,7 +377,9 @@ class AuthManager {
322
377
  const userToken = {
323
378
  id: decodedToken.id,
324
379
  iss: decodedToken.iss,
325
- sub: typeof decodedToken.sub === 'string' ? parseInt(decodedToken.sub) : decodedToken.sub,
380
+ sub: typeof decodedToken.sub === 'string'
381
+ ? parseInt(decodedToken.sub)
382
+ : decodedToken.sub,
326
383
  first_name: decodedToken.first_name,
327
384
  last_name: decodedToken.last_name,
328
385
  email: decodedToken.email,
@@ -331,6 +388,7 @@ class AuthManager {
331
388
  exp: decodedToken.exp,
332
389
  scopes: decodedToken.scopes,
333
390
  realm: decodedToken.realm,
391
+ provider: decodedToken.provider,
334
392
  };
335
393
  const { data: publicKey } = yield axios_1.default.get(`${authServer}public/public_key`);
336
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.9",
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,23 +181,29 @@ export class AuthManager {
170
181
  }
171
182
  }
172
183
 
173
-
174
- public async platformCheck(email: string, token: string): Promise<boolean> {
184
+ public async platformCheck(
185
+ email: string,
186
+ ): Promise<PlatformCheckResponse> {
175
187
  const response = await axios.post(
176
- `${this.authServer}auth/email/platform_check`,
177
- {
178
- realm_name: this.realmName,
179
- email,
180
- },
188
+ `${this.authServer}auth/email/platform_check`,
189
+ {
190
+ realm_name: this.realmName,
191
+ email,
192
+ },
181
193
  );
182
194
  if (response.data.error || response.data.errors) {
183
195
  throw new Error(response.data.error || response.data.message);
184
196
  }
185
197
 
186
- return (response.status === 200) ? response.data : {'platforms': []};
198
+ return response.status === 200
199
+ ? response.data
200
+ : { platforms: [] };
187
201
  }
188
202
 
189
- public async verifyEmail(email: string, token: string): Promise<boolean> {
203
+ public async verifyEmail(
204
+ email: string,
205
+ token: string,
206
+ ): Promise<boolean> {
190
207
  const response = await axios.post(
191
208
  `${this.authServer}auth/email/verify`,
192
209
  {
@@ -202,15 +219,19 @@ export class AuthManager {
202
219
  return response.status === 200;
203
220
  }
204
221
 
205
- 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> {
206
227
  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
- },
228
+ `${this.authServer}auth/email/do_pass_reset`,
229
+ {
230
+ realm_name: this.realmName,
231
+ email,
232
+ token,
233
+ new_password: newPassword,
234
+ },
214
235
  );
215
236
  if (response.data.error || response.data.errors) {
216
237
  throw new Error(response.data.error || response.data.message);
@@ -256,7 +277,85 @@ export class AuthManager {
256
277
  return response.status === 200 || response.status === 201;
257
278
  }
258
279
 
259
- 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> {
260
359
  const accessToken = localStorage.getItem('access_token');
261
360
  if (!accessToken) {
262
361
  throw new Error('Access token not found');
@@ -281,10 +380,10 @@ export class AuthManager {
281
380
  }
282
381
 
283
382
  public async registerUsingEmail(
284
- firstName: string,
285
- lastName: string,
286
- email: string,
287
- password: string
383
+ firstName: string,
384
+ lastName: string,
385
+ email: string,
386
+ password: string,
288
387
  ): Promise<void> {
289
388
  const response = await axios.post(
290
389
  `${this.authServer}auth/email/register`,
@@ -301,27 +400,35 @@ export class AuthManager {
301
400
  }
302
401
 
303
402
  if (!response.data.access_token) {
304
- throw new Error('Something went wrong');
403
+ throw new Error('Something went wrong');
305
404
  }
306
405
 
307
406
  this.saveTokens(response, false);
308
407
  }
309
408
 
310
- private saveTokens(response: AxiosResponse, byRefresh: boolean): void {
409
+ private saveTokens(
410
+ response: AxiosResponse,
411
+ byRefresh: boolean,
412
+ ): void {
311
413
  localStorage.setItem('access_token', response.data.access_token);
312
414
  localStorage.setItem(
313
415
  'refresh_token',
314
416
  response.data.refresh_token,
315
417
  );
316
418
  this.onStateChange({
317
- type: byRefresh ? AuthEventType.USER_UPDATED : AuthEventType.USER_LOGGED_IN,
419
+ type: byRefresh
420
+ ? AuthEventType.USER_UPDATED
421
+ : AuthEventType.USER_LOGGED_IN,
318
422
  user: this.tokenToPayload(response.data.access_token),
319
- });
423
+ });
320
424
  const user = this.tokenToPayload(response.data.access_token);
321
425
  localStorage.setItem('user', JSON.stringify(user));
322
426
  }
323
427
 
324
- public async loginUsingEmail(email: string, password: string): Promise<void> {
428
+ public async loginUsingEmail(
429
+ email: string,
430
+ password: string,
431
+ ): Promise<void> {
325
432
  const response = await axios.post(
326
433
  `${this.authServer}auth/email/login`,
327
434
  {
@@ -394,18 +501,22 @@ export class AuthManager {
394
501
  }
395
502
 
396
503
  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
- }
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
+ };
409
520
 
410
521
  const { data: publicKey } = await axios.get(
411
522
  `${authServer}public/public_key`,
@@ -419,7 +530,7 @@ export class AuthManager {
419
530
  const { data: revokedIds } = await axios.get(
420
531
  `${authServer}public/revoked_ids`,
421
532
  );
422
- if(revokedIds.includes(decodedToken.id)){
533
+ if (revokedIds.includes(decodedToken.id)) {
423
534
  throw new Error('Token is revoked');
424
535
  }
425
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
+ }