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

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.
@@ -11,14 +11,21 @@ export declare class AuthManager {
11
11
  private tokenToPayload;
12
12
  private toBase64Url;
13
13
  private generatePKCEPair;
14
- refreshAccessToken(isInitilization?: boolean): Promise<string>;
14
+ refreshAccessToken(isInitialization?: boolean): Promise<string>;
15
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
+ verifyEmail(email: string, token: string): Promise<boolean>;
22
+ doPassReset(email: string, token: string, newPassword: string): Promise<boolean>;
23
+ changeEmail(email: string): Promise<boolean>;
24
+ initPasswordReset(email: string): Promise<boolean>;
25
+ changePassword(oldPassword: string, newPassword: string, email: string): Promise<boolean>;
26
+ registerUsingEmail(firstName: string, lastName: string, email: string, password: string): Promise<void>;
21
27
  private saveTokens;
28
+ loginUsingEmail(email: string, password: string): Promise<void>;
22
29
  loginUsingPkce(code: string): Promise<void>;
23
30
  logout(): Promise<void>;
24
31
  static validateToken(authServer: string, bearerToken: string): Promise<UserTokenPayload>;
@@ -63,7 +63,7 @@ class AuthManager {
63
63
  return { verifier, challenge };
64
64
  }
65
65
  refreshAccessToken() {
66
- return __awaiter(this, arguments, void 0, function* (isInitilization = false) {
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,7 +79,7 @@ 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
- if (!isInitilization) {
82
+ if (!isInitialization) {
83
83
  // throw refresh fail only if not initialization
84
84
  this.onStateChange({ type: types_1.AuthEventType.REFRESH_FAILED });
85
85
  }
@@ -139,6 +139,101 @@ class AuthManager {
139
139
  }
140
140
  });
141
141
  }
142
+ verifyEmail(email, token) {
143
+ return __awaiter(this, void 0, void 0, function* () {
144
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/verify`, {
145
+ realm_name: this.realmName,
146
+ email,
147
+ token,
148
+ });
149
+ if (response.data.error || response.data.errors) {
150
+ throw new Error(response.data.error || response.data.message);
151
+ }
152
+ return response.status === 200;
153
+ });
154
+ }
155
+ doPassReset(email, token, newPassword) {
156
+ return __awaiter(this, void 0, void 0, function* () {
157
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/do_pass_reset`, {
158
+ realm_name: this.realmName,
159
+ email,
160
+ token,
161
+ new_password: newPassword,
162
+ });
163
+ if (response.data.error || response.data.errors) {
164
+ throw new Error(response.data.error || response.data.message);
165
+ }
166
+ return response.status === 200;
167
+ });
168
+ }
169
+ changeEmail(email) {
170
+ return __awaiter(this, void 0, void 0, function* () {
171
+ const accessToken = localStorage.getItem('access_token');
172
+ if (!accessToken) {
173
+ throw new Error('Access token not found');
174
+ }
175
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/change_email`, {
176
+ realm_name: this.realmName,
177
+ email,
178
+ }, {
179
+ headers: { Authorization: `Bearer ${accessToken}` },
180
+ });
181
+ if (response.data.error || response.data.errors) {
182
+ throw new Error(response.data.error || response.data.message);
183
+ }
184
+ return response.status === 200;
185
+ });
186
+ }
187
+ initPasswordReset(email) {
188
+ return __awaiter(this, void 0, void 0, function* () {
189
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/init_pass_reset`, {
190
+ realm_name: this.realmName,
191
+ email,
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 || response.status === 201;
197
+ });
198
+ }
199
+ changePassword(oldPassword, newPassword, email) {
200
+ return __awaiter(this, void 0, void 0, function* () {
201
+ const accessToken = localStorage.getItem('access_token');
202
+ if (!accessToken) {
203
+ throw new Error('Access token not found');
204
+ }
205
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/change_pass`, {
206
+ realm_name: this.realmName,
207
+ email,
208
+ old_password: oldPassword,
209
+ new_password: newPassword,
210
+ }, {
211
+ headers: { Authorization: `Bearer ${accessToken}` },
212
+ });
213
+ if (response.data.error || response.data.errors) {
214
+ throw new Error(response.data.error || response.data.message);
215
+ }
216
+ return response.status === 200;
217
+ });
218
+ }
219
+ registerUsingEmail(firstName, lastName, email, password) {
220
+ return __awaiter(this, void 0, void 0, function* () {
221
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/register`, {
222
+ realm_name: this.realmName,
223
+ first_name: firstName,
224
+ last_name: lastName,
225
+ email,
226
+ password,
227
+ });
228
+ if (response.data.message || response.data.error) {
229
+ throw new Error(response.data.message || response.data.error);
230
+ }
231
+ if (!response.data.access_token) {
232
+ throw new Error('Something went wrong');
233
+ }
234
+ this.saveTokens(response, false);
235
+ });
236
+ }
142
237
  saveTokens(response, byRefresh) {
143
238
  localStorage.setItem('access_token', response.data.access_token);
144
239
  localStorage.setItem('refresh_token', response.data.refresh_token);
@@ -149,6 +244,19 @@ class AuthManager {
149
244
  const user = this.tokenToPayload(response.data.access_token);
150
245
  localStorage.setItem('user', JSON.stringify(user));
151
246
  }
247
+ loginUsingEmail(email, password) {
248
+ return __awaiter(this, void 0, void 0, function* () {
249
+ const response = yield axios_1.default.post(`${this.authServer}auth/email/login`, {
250
+ realm_name: this.realmName,
251
+ email,
252
+ password,
253
+ });
254
+ if (response.data.message || response.data.error) {
255
+ throw new Error(response.data.message || response.data.error);
256
+ }
257
+ this.saveTokens(response, false);
258
+ });
259
+ }
152
260
  loginUsingPkce(code) {
153
261
  return __awaiter(this, void 0, void 0, function* () {
154
262
  try {
@@ -200,23 +308,23 @@ class AuthManager {
200
308
  throw new Error('Not a valid jwt token');
201
309
  }
202
310
  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'],
311
+ id: decodedToken.id,
312
+ iss: decodedToken.iss,
313
+ sub: typeof decodedToken.sub === 'string' ? parseInt(decodedToken.sub) : decodedToken.sub,
314
+ first_name: decodedToken.first_name,
315
+ last_name: decodedToken.last_name,
316
+ email: decodedToken.email,
317
+ aud: decodedToken.aud,
318
+ iat: decodedToken.iat,
319
+ exp: decodedToken.exp,
320
+ scopes: decodedToken.scopes,
321
+ realm: decodedToken.realm,
214
322
  };
215
323
  const { data: publicKey } = yield axios_1.default.get(`${authServer}public/public_key`);
216
324
  const { data: algo } = yield axios_1.default.get(`${authServer}public/algo`);
217
325
  (0, jsonwebtoken_1.verify)(bearerToken, publicKey, { algorithms: [algo] });
218
326
  const { data: revokedIds } = yield axios_1.default.get(`${authServer}public/revoked_ids`);
219
- if (revokedIds.includes(decodedToken['id'])) {
327
+ if (revokedIds.includes(decodedToken.id)) {
220
328
  throw new Error('Token is revoked');
221
329
  }
222
330
  return userToken;
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;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "supaapps-auth",
3
- "version": "2.0.0-rc.6",
3
+ "version": "2.0.0-rc.8",
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",
@@ -95,7 +95,7 @@ export class AuthManager {
95
95
  return { verifier, challenge };
96
96
  }
97
97
 
98
- public async refreshAccessToken(isInitilization: boolean = false): 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,7 +114,7 @@ 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
- if (!isInitilization) {
117
+ if (!isInitialization) {
118
118
  // throw refresh fail only if not initialization
119
119
  this.onStateChange({ type: AuthEventType.REFRESH_FAILED });
120
120
  }
@@ -170,6 +170,127 @@ export class AuthManager {
170
170
  }
171
171
  }
172
172
 
173
+ public async verifyEmail(email: string, token: string): Promise<boolean> {
174
+ const response = await axios.post(
175
+ `${this.authServer}auth/email/verify`,
176
+ {
177
+ realm_name: this.realmName,
178
+ email,
179
+ token,
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;
187
+ }
188
+
189
+ public async doPassReset(email: string, token: string, newPassword: string): Promise<boolean> {
190
+ 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
+ },
198
+ );
199
+ if (response.data.error || response.data.errors) {
200
+ throw new Error(response.data.error || response.data.message);
201
+ }
202
+
203
+ return response.status === 200;
204
+ }
205
+
206
+ public async changeEmail(email: string): Promise<boolean> {
207
+ const accessToken = localStorage.getItem('access_token');
208
+ if (!accessToken) {
209
+ throw new Error('Access token not found');
210
+ }
211
+ const response = await axios.post(
212
+ `${this.authServer}auth/email/change_email`,
213
+ {
214
+ realm_name: this.realmName,
215
+ email,
216
+ },
217
+ {
218
+ headers: { Authorization: `Bearer ${accessToken}` },
219
+ },
220
+ );
221
+ if (response.data.error || response.data.errors) {
222
+ throw new Error(response.data.error || response.data.message);
223
+ }
224
+
225
+ return response.status === 200;
226
+ }
227
+
228
+ public async initPasswordReset(email: string): Promise<boolean> {
229
+ const response = await axios.post(
230
+ `${this.authServer}auth/email/init_pass_reset`,
231
+ {
232
+ realm_name: this.realmName,
233
+ email,
234
+ },
235
+ );
236
+ if (response.data.error || response.data.errors) {
237
+ throw new Error(response.data.error || response.data.message);
238
+ }
239
+
240
+ return response.status === 200 || response.status === 201;
241
+ }
242
+
243
+ public async changePassword(oldPassword: string, newPassword: string, email: string): Promise<boolean> {
244
+ const accessToken = localStorage.getItem('access_token');
245
+ if (!accessToken) {
246
+ throw new Error('Access token not found');
247
+ }
248
+ const response = await axios.post(
249
+ `${this.authServer}auth/email/change_pass`,
250
+ {
251
+ realm_name: this.realmName,
252
+ email,
253
+ old_password: oldPassword,
254
+ new_password: newPassword,
255
+ },
256
+ {
257
+ headers: { Authorization: `Bearer ${accessToken}` },
258
+ },
259
+ );
260
+ if (response.data.error || response.data.errors) {
261
+ throw new Error(response.data.error || response.data.message);
262
+ }
263
+
264
+ return response.status === 200;
265
+ }
266
+
267
+ public async registerUsingEmail(
268
+ firstName: string,
269
+ lastName: string,
270
+ email: string,
271
+ password: string
272
+ ): Promise<void> {
273
+ const response = await axios.post(
274
+ `${this.authServer}auth/email/register`,
275
+ {
276
+ realm_name: this.realmName,
277
+ first_name: firstName,
278
+ last_name: lastName,
279
+ email,
280
+ password,
281
+ },
282
+ );
283
+ if (response.data.message || response.data.error) {
284
+ throw new Error(response.data.message || response.data.error);
285
+ }
286
+
287
+ if (!response.data.access_token) {
288
+ throw new Error('Something went wrong');
289
+ }
290
+
291
+ this.saveTokens(response, false);
292
+ }
293
+
173
294
  private saveTokens(response: AxiosResponse, byRefresh: boolean): void {
174
295
  localStorage.setItem('access_token', response.data.access_token);
175
296
  localStorage.setItem(
@@ -184,6 +305,21 @@ export class AuthManager {
184
305
  localStorage.setItem('user', JSON.stringify(user));
185
306
  }
186
307
 
308
+ public async loginUsingEmail(email: string, password: string): Promise<void> {
309
+ const response = await axios.post(
310
+ `${this.authServer}auth/email/login`,
311
+ {
312
+ realm_name: this.realmName,
313
+ email,
314
+ password,
315
+ },
316
+ );
317
+ if (response.data.message || response.data.error) {
318
+ throw new Error(response.data.message || response.data.error);
319
+ }
320
+ this.saveTokens(response, false);
321
+ }
322
+
187
323
  public async loginUsingPkce(code: string): Promise<void> {
188
324
  try {
189
325
  const codeVerifier = localStorage.getItem('codeVerifier');
@@ -235,24 +371,24 @@ export class AuthManager {
235
371
  // @todo add caching for public key and algo
236
372
  const decodedToken = jwtDecode(bearerToken, {
237
373
  complete: true,
238
- })?.payload;
374
+ })?.payload as unknown as UserTokenPayload;
239
375
 
240
376
  if (!decodedToken) {
241
377
  throw new Error('Not a valid jwt token');
242
378
  }
243
379
 
244
380
  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'],
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,
256
392
  }
257
393
 
258
394
  const { data: publicKey } = await axios.get(
@@ -267,7 +403,7 @@ export class AuthManager {
267
403
  const { data: revokedIds } = await axios.get(
268
404
  `${authServer}public/revoked_ids`,
269
405
  );
270
- if(revokedIds.includes(decodedToken['id'])){
406
+ if(revokedIds.includes(decodedToken.id)){
271
407
  throw new Error('Token is revoked');
272
408
  }
273
409
  return userToken;
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;