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.
- package/dist/AuthManager.d.ts +8 -1
- package/dist/AuthManager.js +122 -14
- package/dist/types.d.ts +1 -1
- package/package.json +2 -2
- package/src/AuthManager.ts +151 -15
- package/src/types.ts +1 -1
package/dist/AuthManager.d.ts
CHANGED
|
@@ -11,14 +11,21 @@ export declare class AuthManager {
|
|
|
11
11
|
private tokenToPayload;
|
|
12
12
|
private toBase64Url;
|
|
13
13
|
private generatePKCEPair;
|
|
14
|
-
refreshAccessToken(
|
|
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>;
|
package/dist/AuthManager.js
CHANGED
|
@@ -63,7 +63,7 @@ class AuthManager {
|
|
|
63
63
|
return { verifier, challenge };
|
|
64
64
|
}
|
|
65
65
|
refreshAccessToken() {
|
|
66
|
-
return __awaiter(this, arguments, 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,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 (!
|
|
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
|
|
204
|
-
iss: decodedToken
|
|
205
|
-
sub: parseInt(decodedToken
|
|
206
|
-
first_name: decodedToken
|
|
207
|
-
last_name: decodedToken
|
|
208
|
-
email: decodedToken
|
|
209
|
-
aud: decodedToken
|
|
210
|
-
iat: decodedToken
|
|
211
|
-
exp: decodedToken
|
|
212
|
-
scopes: decodedToken
|
|
213
|
-
realm: decodedToken
|
|
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
|
|
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
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "supaapps-auth",
|
|
3
|
-
"version": "2.0.0-rc.
|
|
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.
|
|
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",
|
package/src/AuthManager.ts
CHANGED
|
@@ -95,7 +95,7 @@ export class AuthManager {
|
|
|
95
95
|
return { verifier, challenge };
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
public async refreshAccessToken(
|
|
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 (!
|
|
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
|
|
246
|
-
iss: decodedToken
|
|
247
|
-
sub: parseInt(decodedToken
|
|
248
|
-
first_name: decodedToken
|
|
249
|
-
last_name: decodedToken
|
|
250
|
-
email: decodedToken
|
|
251
|
-
aud: decodedToken
|
|
252
|
-
iat: decodedToken
|
|
253
|
-
exp: decodedToken
|
|
254
|
-
scopes: decodedToken
|
|
255
|
-
realm: decodedToken
|
|
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
|
|
406
|
+
if(revokedIds.includes(decodedToken.id)){
|
|
271
407
|
throw new Error('Token is revoked');
|
|
272
408
|
}
|
|
273
409
|
return userToken;
|