@dotpress/auth 1.2.0 → 1.3.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.
- package/README.md +76 -0
- package/dist/__tests__/functional/cookies.test.js +235 -0
- package/dist/lib/handlers.js +89 -4
- package/dist/types/types.d.ts +8 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -45,6 +45,7 @@ The plugin will check and parse bearer token from Authorization header and will
|
|
|
45
45
|
|
|
46
46
|
- `POST /auth/login`
|
|
47
47
|
- `POST /auth/refresh`
|
|
48
|
+
- `POST /auth/restore`
|
|
48
49
|
- `GET /auth/me`
|
|
49
50
|
- `POST /auth/logout`
|
|
50
51
|
|
|
@@ -228,6 +229,81 @@ Refresh tokens using previous token pair. The plugin automatically detects the a
|
|
|
228
229
|
- `INVALID_REFRESH_TOKEN`: Refresh token is invalid or already used
|
|
229
230
|
- `EXPIRED_REFRESH_TOKEN`: Refresh token has expired
|
|
230
231
|
|
|
232
|
+
### `POST /auth/restore`
|
|
233
|
+
|
|
234
|
+
Restore a user session from cookies. This endpoint validates the access token from cookies and automatically refreshes it if expired.
|
|
235
|
+
|
|
236
|
+
**Use Case:**
|
|
237
|
+
This route is designed for web applications to restore user sessions after page reload or when returning after inactivity. Instead of making multiple API calls (`/auth/me` → 401 → `/auth/refresh` → `/auth/me`), you can call `/auth/restore` once to validate or refresh the session in a single request.
|
|
238
|
+
|
|
239
|
+
**Requirements:**
|
|
240
|
+
- Cookie mode must be enabled (`cookies.enabled: true`)
|
|
241
|
+
- Access token must be stored in cookies (`cookies.accessTokenInCookie: true`)
|
|
242
|
+
- Both `accessToken` and `refreshToken` must be present in cookies
|
|
243
|
+
|
|
244
|
+
**Request:**
|
|
245
|
+
No body required. Tokens are automatically extracted from cookies.
|
|
246
|
+
|
|
247
|
+
**Response:**
|
|
248
|
+
```json
|
|
249
|
+
{
|
|
250
|
+
"userId": "usr-123",
|
|
251
|
+
"accessToken": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
252
|
+
"refreshToken": "3f7b2a8c1e...",
|
|
253
|
+
"expiresIn": 3600,
|
|
254
|
+
"expiresAt": "2025-11-02T16:30:00.000Z",
|
|
255
|
+
"user": {
|
|
256
|
+
"id": "usr-123",
|
|
257
|
+
"username": "JohnDoe",
|
|
258
|
+
"email": "john@example.com"
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**Behavior:**
|
|
264
|
+
1. If `accessToken` is valid: Returns existing tokens with user data
|
|
265
|
+
2. If `accessToken` is expired but `refreshToken` is valid: Generates new token pair, updates cookies, and returns new tokens with user data
|
|
266
|
+
3. If both tokens are invalid: Returns 401
|
|
267
|
+
|
|
268
|
+
**Error Codes:**
|
|
269
|
+
- `COOKIES_NOT_ENABLED`: Cookie mode is not enabled in plugin configuration
|
|
270
|
+
- `ACCESS_TOKEN_NOT_IN_COOKIE`: `accessTokenInCookie` is not enabled
|
|
271
|
+
- `NO_REFRESH_TOKEN`: Refresh token cookie is missing
|
|
272
|
+
- `NO_ACCESS_TOKEN`: Access token cookie is missing
|
|
273
|
+
- `INVALID_REFRESH_TOKEN`: Refresh token is invalid or already used
|
|
274
|
+
- `EXPIRED_REFRESH_TOKEN`: Refresh token has expired
|
|
275
|
+
- `USER_NOT_FOUND`: User ID from token not found in database
|
|
276
|
+
|
|
277
|
+
**Example Usage:**
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
// React SPA: Restore session on app initialization
|
|
281
|
+
useEffect(() => {
|
|
282
|
+
const restoreSession = async () => {
|
|
283
|
+
try {
|
|
284
|
+
const response = await fetch('/auth/restore', {
|
|
285
|
+
method: 'POST',
|
|
286
|
+
credentials: 'include', // Important: include cookies
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
if (response.ok) {
|
|
290
|
+
const { user, accessToken, expiresAt } = await response.json()
|
|
291
|
+
dispatch(setUser(user))
|
|
292
|
+
dispatch(setAccessToken(accessToken))
|
|
293
|
+
dispatch(setExpiresAt(expiresAt))
|
|
294
|
+
} else {
|
|
295
|
+
// Session invalid, redirect to login
|
|
296
|
+
navigate('/login')
|
|
297
|
+
}
|
|
298
|
+
} catch (error) {
|
|
299
|
+
console.error('Failed to restore session:', error)
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
restoreSession()
|
|
304
|
+
}, [])
|
|
305
|
+
```
|
|
306
|
+
|
|
231
307
|
### `GET /auth/me`
|
|
232
308
|
|
|
233
309
|
Get current authenticated user.
|
|
@@ -383,4 +383,239 @@ describe('Cookie Mode Authentication', () => {
|
|
|
383
383
|
expect(refreshCookie).toContain('Domain=.example.com');
|
|
384
384
|
});
|
|
385
385
|
});
|
|
386
|
+
describe('POST /auth/restore', () => {
|
|
387
|
+
it('should return 401 when cookies are not enabled', async () => {
|
|
388
|
+
const authPluginNoCookies = configurePlugin({
|
|
389
|
+
keys: {
|
|
390
|
+
secretKey: '',
|
|
391
|
+
publicKey: '',
|
|
392
|
+
},
|
|
393
|
+
dataProvider,
|
|
394
|
+
cookies: {
|
|
395
|
+
enabled: false,
|
|
396
|
+
},
|
|
397
|
+
});
|
|
398
|
+
const app = await createApp({
|
|
399
|
+
plugins: [authPluginNoCookies],
|
|
400
|
+
});
|
|
401
|
+
const res = await request(app).post('/auth/restore');
|
|
402
|
+
expect(res.status).toBe(401);
|
|
403
|
+
});
|
|
404
|
+
it('should return 401 when accessTokenInCookie is not enabled', async () => {
|
|
405
|
+
const authPluginNoAccessCookie = configurePlugin({
|
|
406
|
+
keys: {
|
|
407
|
+
secretKey: '',
|
|
408
|
+
publicKey: '',
|
|
409
|
+
},
|
|
410
|
+
dataProvider,
|
|
411
|
+
cookies: {
|
|
412
|
+
enabled: true,
|
|
413
|
+
accessTokenInCookie: false, // Required for restore
|
|
414
|
+
},
|
|
415
|
+
});
|
|
416
|
+
const app = await createApp({
|
|
417
|
+
plugins: [authPluginNoAccessCookie],
|
|
418
|
+
});
|
|
419
|
+
const res = await request(app)
|
|
420
|
+
.post('/auth/restore')
|
|
421
|
+
.set('Cookie', ['dotpress_refresh_token=ref-token']);
|
|
422
|
+
expect(res.status).toBe(401);
|
|
423
|
+
});
|
|
424
|
+
it('should return 401 when refresh token is missing', async () => {
|
|
425
|
+
const authPluginWithAccessCookie = configurePlugin({
|
|
426
|
+
keys: {
|
|
427
|
+
secretKey: '',
|
|
428
|
+
publicKey: '',
|
|
429
|
+
},
|
|
430
|
+
dataProvider,
|
|
431
|
+
cookies: {
|
|
432
|
+
enabled: true,
|
|
433
|
+
accessTokenInCookie: true,
|
|
434
|
+
},
|
|
435
|
+
});
|
|
436
|
+
const app = await createApp({
|
|
437
|
+
plugins: [authPluginWithAccessCookie],
|
|
438
|
+
});
|
|
439
|
+
const res = await request(app)
|
|
440
|
+
.post('/auth/restore')
|
|
441
|
+
.set('Cookie', ['dotpress_access_token=acc-token']);
|
|
442
|
+
expect(res.status).toBe(401);
|
|
443
|
+
});
|
|
444
|
+
it('should return 401 when access token is missing', async () => {
|
|
445
|
+
const authPluginWithAccessCookie = configurePlugin({
|
|
446
|
+
keys: {
|
|
447
|
+
secretKey: '',
|
|
448
|
+
publicKey: '',
|
|
449
|
+
},
|
|
450
|
+
dataProvider,
|
|
451
|
+
cookies: {
|
|
452
|
+
enabled: true,
|
|
453
|
+
accessTokenInCookie: true,
|
|
454
|
+
},
|
|
455
|
+
});
|
|
456
|
+
const app = await createApp({
|
|
457
|
+
plugins: [authPluginWithAccessCookie],
|
|
458
|
+
});
|
|
459
|
+
const res = await request(app)
|
|
460
|
+
.post('/auth/restore')
|
|
461
|
+
.set('Cookie', ['dotpress_refresh_token=ref-token']);
|
|
462
|
+
expect(res.status).toBe(401);
|
|
463
|
+
});
|
|
464
|
+
it('should return user and tokens when access token is still valid', async () => {
|
|
465
|
+
vi.spyOn(tokenFns, 'validateAndDecodeAccessToken').mockReturnValue({
|
|
466
|
+
userId: 'usr-123',
|
|
467
|
+
});
|
|
468
|
+
vi.mocked(dataProvider.findUserById).mockResolvedValue({
|
|
469
|
+
id: 'usr-123',
|
|
470
|
+
username: 'JohnDoe',
|
|
471
|
+
email: 'john@example.com',
|
|
472
|
+
});
|
|
473
|
+
const authPluginWithAccessCookie = configurePlugin({
|
|
474
|
+
keys: {
|
|
475
|
+
secretKey: '',
|
|
476
|
+
publicKey: '',
|
|
477
|
+
},
|
|
478
|
+
dataProvider,
|
|
479
|
+
cookies: {
|
|
480
|
+
enabled: true,
|
|
481
|
+
accessTokenInCookie: true,
|
|
482
|
+
},
|
|
483
|
+
});
|
|
484
|
+
const app = await createApp({
|
|
485
|
+
plugins: [authPluginWithAccessCookie],
|
|
486
|
+
});
|
|
487
|
+
const res = await request(app)
|
|
488
|
+
.post('/auth/restore')
|
|
489
|
+
.set('Cookie', [
|
|
490
|
+
'dotpress_access_token=valid-access-token',
|
|
491
|
+
'dotpress_refresh_token=valid-refresh-token',
|
|
492
|
+
]);
|
|
493
|
+
expect(res.status).toBe(200);
|
|
494
|
+
expect(res.body).toMatchObject({
|
|
495
|
+
userId: 'usr-123',
|
|
496
|
+
accessToken: 'valid-access-token',
|
|
497
|
+
refreshToken: 'valid-refresh-token',
|
|
498
|
+
expiresIn: expect.any(Number),
|
|
499
|
+
expiresAt: expect.any(String),
|
|
500
|
+
user: {
|
|
501
|
+
id: 'usr-123',
|
|
502
|
+
username: 'JohnDoe',
|
|
503
|
+
email: 'john@example.com',
|
|
504
|
+
},
|
|
505
|
+
});
|
|
506
|
+
});
|
|
507
|
+
it('should refresh tokens and return new tokens when access token is expired', async () => {
|
|
508
|
+
// First call: validateAndDecodeAccessToken throws (expired)
|
|
509
|
+
vi.spyOn(tokenFns, 'validateAndDecodeAccessToken').mockImplementation(() => {
|
|
510
|
+
throw new Error('Token expired');
|
|
511
|
+
});
|
|
512
|
+
// Second call: generateTokensFromRefreshToken returns new tokens
|
|
513
|
+
vi.spyOn(tokenFns, 'generateTokensFromRefreshToken').mockResolvedValue({
|
|
514
|
+
userId: 'usr-456',
|
|
515
|
+
accessToken: 'new-access-token',
|
|
516
|
+
refreshToken: 'new-refresh-token',
|
|
517
|
+
});
|
|
518
|
+
vi.mocked(dataProvider.findUserById).mockResolvedValue({
|
|
519
|
+
id: 'usr-456',
|
|
520
|
+
username: 'JaneDoe',
|
|
521
|
+
email: 'jane@example.com',
|
|
522
|
+
});
|
|
523
|
+
const authPluginWithAccessCookie = configurePlugin({
|
|
524
|
+
keys: {
|
|
525
|
+
secretKey: '',
|
|
526
|
+
publicKey: '',
|
|
527
|
+
},
|
|
528
|
+
dataProvider,
|
|
529
|
+
cookies: {
|
|
530
|
+
enabled: true,
|
|
531
|
+
accessTokenInCookie: true,
|
|
532
|
+
},
|
|
533
|
+
});
|
|
534
|
+
const app = await createApp({
|
|
535
|
+
plugins: [authPluginWithAccessCookie],
|
|
536
|
+
});
|
|
537
|
+
const res = await request(app)
|
|
538
|
+
.post('/auth/restore')
|
|
539
|
+
.set('Cookie', [
|
|
540
|
+
'dotpress_access_token=expired-access-token',
|
|
541
|
+
'dotpress_refresh_token=valid-refresh-token',
|
|
542
|
+
]);
|
|
543
|
+
expect(res.status).toBe(200);
|
|
544
|
+
expect(res.body).toMatchObject({
|
|
545
|
+
userId: 'usr-456',
|
|
546
|
+
accessToken: 'new-access-token',
|
|
547
|
+
refreshToken: 'new-refresh-token',
|
|
548
|
+
expiresIn: expect.any(Number),
|
|
549
|
+
expiresAt: expect.any(String),
|
|
550
|
+
user: {
|
|
551
|
+
id: 'usr-456',
|
|
552
|
+
username: 'JaneDoe',
|
|
553
|
+
email: 'jane@example.com',
|
|
554
|
+
},
|
|
555
|
+
});
|
|
556
|
+
// Verify new cookies were set
|
|
557
|
+
expect(res.headers['set-cookie']).toBeDefined();
|
|
558
|
+
const cookies = Array.isArray(res.headers['set-cookie'])
|
|
559
|
+
? res.headers['set-cookie']
|
|
560
|
+
: [res.headers['set-cookie']];
|
|
561
|
+
const accessCookie = cookies.find((c) => c.startsWith('dotpress_access_token='));
|
|
562
|
+
const refreshCookie = cookies.find((c) => c.startsWith('dotpress_refresh_token='));
|
|
563
|
+
expect(accessCookie).toBeDefined();
|
|
564
|
+
expect(refreshCookie).toBeDefined();
|
|
565
|
+
});
|
|
566
|
+
it('should return 401 when refresh token is invalid', async () => {
|
|
567
|
+
vi.spyOn(tokenFns, 'validateAndDecodeAccessToken').mockImplementation(() => {
|
|
568
|
+
throw new Error('Token expired');
|
|
569
|
+
});
|
|
570
|
+
vi.spyOn(tokenFns, 'generateTokensFromRefreshToken').mockRejectedValue(new Error('Invalid_Refresh_Token'));
|
|
571
|
+
const authPluginWithAccessCookie = configurePlugin({
|
|
572
|
+
keys: {
|
|
573
|
+
secretKey: '',
|
|
574
|
+
publicKey: '',
|
|
575
|
+
},
|
|
576
|
+
dataProvider,
|
|
577
|
+
cookies: {
|
|
578
|
+
enabled: true,
|
|
579
|
+
accessTokenInCookie: true,
|
|
580
|
+
},
|
|
581
|
+
});
|
|
582
|
+
const app = await createApp({
|
|
583
|
+
plugins: [authPluginWithAccessCookie],
|
|
584
|
+
});
|
|
585
|
+
const res = await request(app)
|
|
586
|
+
.post('/auth/restore')
|
|
587
|
+
.set('Cookie', [
|
|
588
|
+
'dotpress_access_token=expired-access-token',
|
|
589
|
+
'dotpress_refresh_token=invalid-refresh-token',
|
|
590
|
+
]);
|
|
591
|
+
expect(res.status).toBe(401);
|
|
592
|
+
});
|
|
593
|
+
it('should return 401 when refresh token is expired', async () => {
|
|
594
|
+
vi.spyOn(tokenFns, 'validateAndDecodeAccessToken').mockImplementation(() => {
|
|
595
|
+
throw new Error('Token expired');
|
|
596
|
+
});
|
|
597
|
+
vi.spyOn(tokenFns, 'generateTokensFromRefreshToken').mockRejectedValue(new Error('Expired_Refresh_Token'));
|
|
598
|
+
const authPluginWithAccessCookie = configurePlugin({
|
|
599
|
+
keys: {
|
|
600
|
+
secretKey: '',
|
|
601
|
+
publicKey: '',
|
|
602
|
+
},
|
|
603
|
+
dataProvider,
|
|
604
|
+
cookies: {
|
|
605
|
+
enabled: true,
|
|
606
|
+
accessTokenInCookie: true,
|
|
607
|
+
},
|
|
608
|
+
});
|
|
609
|
+
const app = await createApp({
|
|
610
|
+
plugins: [authPluginWithAccessCookie],
|
|
611
|
+
});
|
|
612
|
+
const res = await request(app)
|
|
613
|
+
.post('/auth/restore')
|
|
614
|
+
.set('Cookie', [
|
|
615
|
+
'dotpress_access_token=expired-access-token',
|
|
616
|
+
'dotpress_refresh_token=expired-refresh-token',
|
|
617
|
+
]);
|
|
618
|
+
expect(res.status).toBe(401);
|
|
619
|
+
});
|
|
620
|
+
});
|
|
386
621
|
});
|
package/dist/lib/handlers.js
CHANGED
|
@@ -2,8 +2,8 @@ import { unauthorizedError, internalError } from 'dotpress';
|
|
|
2
2
|
import bcrypt from 'bcryptjs';
|
|
3
3
|
import { getSettings } from './settings.js';
|
|
4
4
|
import { getRequestIp } from './ip.js';
|
|
5
|
-
import { generateTokensForUser, generateTokensFromRefreshToken, } from './tokens.js';
|
|
6
|
-
import { setAuthCookies, clearAuthCookies, extractTokensFromRequest, calculateExpiration, } from './cookies.js';
|
|
5
|
+
import { generateTokensForUser, generateTokensFromRefreshToken, validateAndDecodeAccessToken, } from './tokens.js';
|
|
6
|
+
import { setAuthCookies, clearAuthCookies, extractTokensFromRequest, calculateExpiration, getCookieSettings, } from './cookies.js';
|
|
7
7
|
export const registerHandlers = (plugin) => {
|
|
8
8
|
const authGroup = plugin.addGroup('/auth');
|
|
9
9
|
const settings = getSettings();
|
|
@@ -81,7 +81,7 @@ export const registerHandlers = (plugin) => {
|
|
|
81
81
|
});
|
|
82
82
|
}
|
|
83
83
|
if (mode === 'cookie') {
|
|
84
|
-
setAuthCookies(res, { accessToken, refreshToken }, settings.
|
|
84
|
+
setAuthCookies(res, { accessToken, refreshToken }, settings.refreshTokenTTLInDays * 24 * 60 * 60);
|
|
85
85
|
}
|
|
86
86
|
const expiration = calculateExpiration(settings.accessTokenTTL);
|
|
87
87
|
return {
|
|
@@ -130,7 +130,7 @@ export const registerHandlers = (plugin) => {
|
|
|
130
130
|
setAuthCookies(res, {
|
|
131
131
|
accessToken: tokens.accessToken,
|
|
132
132
|
refreshToken: tokens.refreshToken,
|
|
133
|
-
}, settings.
|
|
133
|
+
}, settings.refreshTokenTTLInDays * 24 * 60 * 60);
|
|
134
134
|
}
|
|
135
135
|
const expiration = calculateExpiration(settings.accessTokenTTL);
|
|
136
136
|
return {
|
|
@@ -162,6 +162,91 @@ export const registerHandlers = (plugin) => {
|
|
|
162
162
|
return req.user;
|
|
163
163
|
},
|
|
164
164
|
});
|
|
165
|
+
authGroup.defineRoute({
|
|
166
|
+
method: 'post',
|
|
167
|
+
path: '/restore',
|
|
168
|
+
schema: (z) => ({
|
|
169
|
+
response: z.object({
|
|
170
|
+
userId: z.string(),
|
|
171
|
+
accessToken: z.string(),
|
|
172
|
+
refreshToken: z.string(),
|
|
173
|
+
expiresIn: z.number(),
|
|
174
|
+
expiresAt: z.string(),
|
|
175
|
+
user: z.unknown(),
|
|
176
|
+
}),
|
|
177
|
+
}),
|
|
178
|
+
handler: async ({ req, res }) => {
|
|
179
|
+
const cookieSettings = getCookieSettings();
|
|
180
|
+
// Only support cookie mode for restore
|
|
181
|
+
if (!cookieSettings.enabled) {
|
|
182
|
+
return unauthorizedError('COOKIES_NOT_ENABLED');
|
|
183
|
+
}
|
|
184
|
+
// This endpoint requires accessTokenInCookie to be enabled
|
|
185
|
+
if (!cookieSettings.accessTokenInCookie) {
|
|
186
|
+
return unauthorizedError('ACCESS_TOKEN_NOT_IN_COOKIE');
|
|
187
|
+
}
|
|
188
|
+
const refreshToken = req.cookies?.[cookieSettings.refreshTokenName];
|
|
189
|
+
const accessToken = req.cookies?.[cookieSettings.accessTokenName];
|
|
190
|
+
if (!refreshToken) {
|
|
191
|
+
return unauthorizedError('NO_REFRESH_TOKEN');
|
|
192
|
+
}
|
|
193
|
+
if (!accessToken) {
|
|
194
|
+
return unauthorizedError('NO_ACCESS_TOKEN');
|
|
195
|
+
}
|
|
196
|
+
// Try to validate access token first
|
|
197
|
+
try {
|
|
198
|
+
const { userId } = validateAndDecodeAccessToken(accessToken);
|
|
199
|
+
const user = await settings.dataProvider.findUserById(userId);
|
|
200
|
+
if (user) {
|
|
201
|
+
const expiration = calculateExpiration(settings.accessTokenTTL);
|
|
202
|
+
return {
|
|
203
|
+
userId,
|
|
204
|
+
accessToken,
|
|
205
|
+
refreshToken,
|
|
206
|
+
...expiration,
|
|
207
|
+
user,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
// Access token is invalid or expired, continue to refresh logic
|
|
213
|
+
}
|
|
214
|
+
// Access token is expired, try to refresh using refresh token
|
|
215
|
+
try {
|
|
216
|
+
const tokens = await generateTokensFromRefreshToken({
|
|
217
|
+
accessToken,
|
|
218
|
+
refreshToken,
|
|
219
|
+
});
|
|
220
|
+
// Set new cookies
|
|
221
|
+
setAuthCookies(res, {
|
|
222
|
+
accessToken: tokens.accessToken,
|
|
223
|
+
refreshToken: tokens.refreshToken,
|
|
224
|
+
}, settings.refreshTokenTTLInDays * 24 * 60 * 60);
|
|
225
|
+
const user = await settings.dataProvider.findUserById(tokens.userId);
|
|
226
|
+
if (!user) {
|
|
227
|
+
return unauthorizedError('USER_NOT_FOUND');
|
|
228
|
+
}
|
|
229
|
+
const expiration = calculateExpiration(settings.accessTokenTTL);
|
|
230
|
+
return {
|
|
231
|
+
userId: tokens.userId,
|
|
232
|
+
accessToken: tokens.accessToken,
|
|
233
|
+
refreshToken: tokens.refreshToken,
|
|
234
|
+
...expiration,
|
|
235
|
+
user,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
catch (e) {
|
|
239
|
+
const errorMessage = e.message;
|
|
240
|
+
if (errorMessage === 'Invalid_Refresh_Token') {
|
|
241
|
+
return unauthorizedError('INVALID_REFRESH_TOKEN');
|
|
242
|
+
}
|
|
243
|
+
if (errorMessage === 'Expired_Refresh_Token') {
|
|
244
|
+
return unauthorizedError('EXPIRED_REFRESH_TOKEN');
|
|
245
|
+
}
|
|
246
|
+
return internalError('Cannot restore session.');
|
|
247
|
+
}
|
|
248
|
+
},
|
|
249
|
+
});
|
|
165
250
|
authGroup.defineRoute({
|
|
166
251
|
method: 'post',
|
|
167
252
|
path: '/logout',
|
package/dist/types/types.d.ts
CHANGED
|
@@ -65,6 +65,14 @@ export type TokenResponse = {
|
|
|
65
65
|
expiresIn: number;
|
|
66
66
|
expiresAt: string;
|
|
67
67
|
};
|
|
68
|
+
export type RestoreResponse = {
|
|
69
|
+
userId: string;
|
|
70
|
+
accessToken: string;
|
|
71
|
+
refreshToken: string;
|
|
72
|
+
expiresIn: number;
|
|
73
|
+
expiresAt: string;
|
|
74
|
+
user: unknown;
|
|
75
|
+
};
|
|
68
76
|
export type CreateTokenPayload = {
|
|
69
77
|
sub: string;
|
|
70
78
|
username: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dotpress/auth",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "JWT Authentication plugin for Dotpress library",
|
|
5
5
|
"author": "Renaud Guyon",
|
|
6
6
|
"license": "MIT",
|
|
@@ -70,5 +70,6 @@
|
|
|
70
70
|
"jwt",
|
|
71
71
|
"plugin",
|
|
72
72
|
"dotpress"
|
|
73
|
-
]
|
|
73
|
+
],
|
|
74
|
+
"packageManager": "pnpm@10.8.1+sha512.c50088ba998c67b8ca8c99df8a5e02fd2ae2e2b29aaf238feaa9e124248d3f48f9fb6db2424949ff901cffbb5e0f0cc1ad6aedb602cd29450751d11c35023677"
|
|
74
75
|
}
|