sentri 1.0.5 → 1.0.6
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 +87 -37
- package/dist/client.d.ts +34 -75
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +0 -7
- package/dist/client.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/libs/config.d.ts +45 -1
- package/dist/libs/config.d.ts.map +1 -1
- package/dist/libs/config.js +40 -2
- package/dist/libs/config.js.map +1 -1
- package/dist/libs/hash.d.ts +14 -0
- package/dist/libs/hash.d.ts.map +1 -1
- package/dist/libs/hash.js +14 -0
- package/dist/libs/hash.js.map +1 -1
- package/dist/libs/token.d.ts +37 -0
- package/dist/libs/token.d.ts.map +1 -1
- package/dist/libs/token.js +63 -0
- package/dist/libs/token.js.map +1 -1
- package/dist/middleware/authorize.d.ts +15 -0
- package/dist/middleware/authorize.d.ts.map +1 -1
- package/dist/middleware/authorize.js +15 -0
- package/dist/middleware/authorize.js.map +1 -1
- package/dist/middleware/protect.d.ts +17 -0
- package/dist/middleware/protect.d.ts.map +1 -1
- package/dist/middleware/protect.js +17 -0
- package/dist/middleware/protect.js.map +1 -1
- package/dist/middleware/router.d.ts +10 -6
- package/dist/middleware/router.d.ts.map +1 -1
- package/dist/middleware/router.js +24 -14
- package/dist/middleware/router.js.map +1 -1
- package/dist/services/auth.d.ts +75 -0
- package/dist/services/auth.d.ts.map +1 -1
- package/dist/services/auth.js +75 -0
- package/dist/services/auth.js.map +1 -1
- package/dist/types/auth.d.ts +144 -0
- package/dist/types/auth.d.ts.map +1 -1
- package/package.json +11 -3
- package/templates/drizzle/adapter.ts +3 -9
- package/templates/drizzle/auth.ts +20 -0
- package/templates/prisma/adapter.ts +3 -9
- package/templates/prisma/auth.ts +20 -0
package/README.md
CHANGED
|
@@ -10,6 +10,7 @@ Auth and authorization library for Express + PostgreSQL. Provides JWT-based auth
|
|
|
10
10
|
- [Quick Start](#quick-start)
|
|
11
11
|
- [CLI](#cli)
|
|
12
12
|
- [Configuration](#configuration)
|
|
13
|
+
- [Custom Route Handlers](#custom-route-handlers)
|
|
13
14
|
- [Adapter Interface](#adapter-interface)
|
|
14
15
|
- [Pre-built Router](#pre-built-router)
|
|
15
16
|
- [Middleware](#middleware)
|
|
@@ -115,6 +116,15 @@ export const auth = createAuth({
|
|
|
115
116
|
// sameSite: 'strict', // default: 'strict'
|
|
116
117
|
// path: '/', // default: '/'
|
|
117
118
|
},
|
|
119
|
+
|
|
120
|
+
// router: { // optional — replace built-in service logic per route
|
|
121
|
+
// login: async (input) => { ... },
|
|
122
|
+
// signup: async (input) => { ... },
|
|
123
|
+
// refresh: async (refreshToken) => { ... },
|
|
124
|
+
// logout: async (refreshToken) => { ... },
|
|
125
|
+
// logoutAll: async (userId) => { ... },
|
|
126
|
+
// assignRoles: async (userId, roles) => { ... },
|
|
127
|
+
// },
|
|
118
128
|
});
|
|
119
129
|
```
|
|
120
130
|
|
|
@@ -124,6 +134,67 @@ When `cookie` is configured, the refresh token is stored in an httpOnly cookie a
|
|
|
124
134
|
|
|
125
135
|
---
|
|
126
136
|
|
|
137
|
+
## Custom Route Handlers
|
|
138
|
+
|
|
139
|
+
The `router` field in config lets you replace the built-in service logic for individual routes while the router still handles request parsing, input validation, and response formatting.
|
|
140
|
+
|
|
141
|
+
Each key is optional — only override what you need. Any key you omit falls back to the built-in behaviour.
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { createAuth, AuthError } from 'sentri';
|
|
145
|
+
import type { AuthResult } from 'sentri';
|
|
146
|
+
|
|
147
|
+
export const auth = createAuth({
|
|
148
|
+
secret: process.env.JWT_SECRET!,
|
|
149
|
+
validRoles: ['user', 'admin'] as const,
|
|
150
|
+
adapter: myAdapter,
|
|
151
|
+
|
|
152
|
+
router: {
|
|
153
|
+
// Add an OTP check before issuing tokens
|
|
154
|
+
login: async (input): Promise<AuthResult> => {
|
|
155
|
+
const otpVerified = await redis.get(`otp:${input.identifier}`);
|
|
156
|
+
if (!otpVerified) {
|
|
157
|
+
return { success: false, error: new AuthError('INVALID_CREDENTIALS', 'OTP required') };
|
|
158
|
+
}
|
|
159
|
+
return defaultLogin(input);
|
|
160
|
+
},
|
|
161
|
+
|
|
162
|
+
// Send a welcome email after signup
|
|
163
|
+
signup: async (input) => {
|
|
164
|
+
const result = await defaultSignup(input);
|
|
165
|
+
if (result.success) {
|
|
166
|
+
await emailService.sendWelcome(input.identifier);
|
|
167
|
+
}
|
|
168
|
+
return result;
|
|
169
|
+
},
|
|
170
|
+
|
|
171
|
+
// Audit-log every token rotation
|
|
172
|
+
refresh: async (refreshToken) => {
|
|
173
|
+
const result = await defaultRefresh(refreshToken);
|
|
174
|
+
if (result.success) {
|
|
175
|
+
await auditLog.record('token_rotated', result.user.id);
|
|
176
|
+
}
|
|
177
|
+
return result;
|
|
178
|
+
},
|
|
179
|
+
},
|
|
180
|
+
});
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
### Available handler signatures
|
|
184
|
+
|
|
185
|
+
| Key | Signature | Must return |
|
|
186
|
+
|---|---|---|
|
|
187
|
+
| `signup` | `(input: SignupInput) => Promise<SignupResult>` | `SignupResult` |
|
|
188
|
+
| `login` | `(input: LoginInput) => Promise<AuthResult>` | `AuthResult` |
|
|
189
|
+
| `refresh` | `(refreshToken: string) => Promise<RefreshResult>` | `RefreshResult` |
|
|
190
|
+
| `logout` | `(refreshToken: string \| undefined) => Promise<void>` | `void` |
|
|
191
|
+
| `logoutAll` | `(userId: string) => Promise<void>` | `void` |
|
|
192
|
+
| `assignRoles` | `(userId: string, roles: string[]) => Promise<AssignRolesResult>` | `AssignRolesResult` |
|
|
193
|
+
|
|
194
|
+
The router always validates the request body and URL parameters before calling any handler. Your function receives the already-validated, trimmed input.
|
|
195
|
+
|
|
196
|
+
---
|
|
197
|
+
|
|
127
198
|
## Adapter Interface
|
|
128
199
|
|
|
129
200
|
The adapter connects sentri to your database. Implement `AuthAdapter` for any ORM or data layer.
|
|
@@ -168,7 +239,7 @@ import { createAdapter } from './adapter.js';
|
|
|
168
239
|
export const adapter = createAdapter(db);
|
|
169
240
|
```
|
|
170
241
|
|
|
171
|
-
`createAdapter` throws
|
|
242
|
+
`createAdapter` throws `AuthError` with code `CONFIGURATION_ERROR` at runtime if called without a `db` argument.
|
|
172
243
|
|
|
173
244
|
---
|
|
174
245
|
|
|
@@ -284,11 +355,11 @@ Status: 200
|
|
|
284
355
|
|
|
285
356
|
### `auth.protect()`
|
|
286
357
|
|
|
287
|
-
Verifies the `Authorization: Bearer <token>` header and injects `
|
|
358
|
+
Verifies the `Authorization: Bearer <token>` header and injects `request.user` into the request.
|
|
288
359
|
|
|
289
360
|
```typescript
|
|
290
|
-
router.get('/dashboard', auth.protect(), (
|
|
291
|
-
|
|
361
|
+
router.get('/dashboard', auth.protect(), (request, response) => {
|
|
362
|
+
response.json(request.user); // { id, identifier, roles }
|
|
292
363
|
});
|
|
293
364
|
```
|
|
294
365
|
|
|
@@ -341,43 +412,21 @@ router.delete(
|
|
|
341
412
|
|
|
342
413
|
## Programmatic API
|
|
343
414
|
|
|
344
|
-
|
|
415
|
+
Token and password utilities are available on the auth client for use outside the built-in router.
|
|
345
416
|
|
|
346
417
|
```typescript
|
|
347
|
-
// Auth
|
|
348
|
-
const result = await auth.signup({ identifier: 'user@example.com', password: 'secret123' });
|
|
349
|
-
const result = await auth.login({ identifier: 'user@example.com', password: 'secret123' });
|
|
350
|
-
const result = await auth.refresh(refreshToken);
|
|
351
|
-
await auth.logout(refreshToken);
|
|
352
|
-
await auth.logoutAll(userId);
|
|
353
|
-
|
|
354
|
-
// Roles
|
|
355
|
-
const result = await auth.assignRoles(userId, ['admin']);
|
|
356
|
-
// Merges with existing roles — result.user.roles has the full updated list
|
|
357
|
-
|
|
358
418
|
// Token utilities
|
|
359
419
|
const accessToken = auth.signAccessToken({ id, identifier, roles });
|
|
360
420
|
const user = auth.verifyAccessToken(accessToken); // throws AuthError if invalid
|
|
361
421
|
const { sessionId } = auth.verifyRefreshToken(token); // throws AuthError if invalid
|
|
422
|
+
const refreshToken = auth.signRefreshToken(sessionId);
|
|
362
423
|
|
|
363
424
|
// Password utilities
|
|
364
425
|
const hash = await auth.hashPassword('secret123');
|
|
365
426
|
const valid = await auth.verifyPassword('secret123', hash);
|
|
366
427
|
```
|
|
367
428
|
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
```typescript
|
|
371
|
-
const result = await auth.login({ identifier, password });
|
|
372
|
-
|
|
373
|
-
if (!result.success) {
|
|
374
|
-
console.error(result.error.code); // 'INVALID_CREDENTIALS'
|
|
375
|
-
console.error(result.error.message);
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
const { accessToken, refreshToken, user } = result;
|
|
380
|
-
```
|
|
429
|
+
`verifyAccessToken` and `verifyRefreshToken` throw `AuthError` with code `TOKEN_EXPIRED` or `TOKEN_INVALID` — wrap them in a try/catch or use the router which handles this automatically.
|
|
381
430
|
|
|
382
431
|
---
|
|
383
432
|
|
|
@@ -396,6 +445,7 @@ import type {
|
|
|
396
445
|
ApiResponse,
|
|
397
446
|
SignupInput,
|
|
398
447
|
LoginInput,
|
|
448
|
+
RouterHandlers,
|
|
399
449
|
UserRecord,
|
|
400
450
|
SessionRecord,
|
|
401
451
|
CreateUserData,
|
|
@@ -432,17 +482,17 @@ The built-in router converts all `AuthError` instances to the standard envelope
|
|
|
432
482
|
```typescript
|
|
433
483
|
import { AuthError } from 'sentri';
|
|
434
484
|
|
|
435
|
-
app.use((
|
|
436
|
-
if (
|
|
485
|
+
app.use((error, _request, response, next) => {
|
|
486
|
+
if (error instanceof AuthError) {
|
|
437
487
|
const status =
|
|
438
|
-
|
|
439
|
-
:
|
|
440
|
-
:
|
|
441
|
-
:
|
|
488
|
+
error.code === 'UNAUTHORIZED' || error.code === 'TOKEN_EXPIRED' || error.code === 'TOKEN_INVALID' || error.code === 'INVALID_CREDENTIALS' ? 401
|
|
489
|
+
: error.code === 'FORBIDDEN' ? 403
|
|
490
|
+
: error.code === 'USER_NOT_FOUND' ? 404
|
|
491
|
+
: error.code === 'USER_ALREADY_EXISTS' ? 409
|
|
442
492
|
: 400;
|
|
443
493
|
|
|
444
|
-
return
|
|
494
|
+
return response.status(status).json({ error: true, statusCode: status, message: error.message, data: null });
|
|
445
495
|
}
|
|
446
|
-
next(
|
|
496
|
+
next(error);
|
|
447
497
|
});
|
|
448
498
|
```
|
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { PermitCheck, PermitOptions } from './middleware/permit.js';
|
|
2
|
-
import type {
|
|
2
|
+
import type { AuthConfig, AuthUser } from './types/auth.js';
|
|
3
3
|
import type { RequestHandler, Router } from 'express';
|
|
4
4
|
/**
|
|
5
5
|
* The bound auth client returned by {@link createAuth}.
|
|
@@ -8,52 +8,9 @@ import type { RequestHandler, Router } from 'express';
|
|
|
8
8
|
* you never need to pass config around yourself.
|
|
9
9
|
*
|
|
10
10
|
* `TRole` is inferred from `validRoles` and narrows role strings to your
|
|
11
|
-
* application's exact union type everywhere (
|
|
11
|
+
* application's exact union type everywhere (authorize, req.user, etc.).
|
|
12
12
|
*/
|
|
13
13
|
export interface AuthClient<TRole extends string = string> {
|
|
14
|
-
/**
|
|
15
|
-
* Register a new user.
|
|
16
|
-
*
|
|
17
|
-
* Validates that every requested role is in `validRoles`, rejects duplicate
|
|
18
|
-
* identifiers, hashes the password, creates the user record, and returns the
|
|
19
|
-
* created user. No tokens are issued — call `login` after signup.
|
|
20
|
-
*/
|
|
21
|
-
signup(input: SignupInput<TRole>): Promise<SignupResult<TRole>>;
|
|
22
|
-
/**
|
|
23
|
-
* Authenticate an existing user by email and password.
|
|
24
|
-
*
|
|
25
|
-
* On success, creates a new session and returns an access + refresh token pair.
|
|
26
|
-
* Returns `{ success: false, error }` with code `INVALID_CREDENTIALS` on any
|
|
27
|
-
* mismatch (intentionally vague to prevent user enumeration).
|
|
28
|
-
*/
|
|
29
|
-
login(input: LoginInput): Promise<AuthResult<TRole>>;
|
|
30
|
-
/**
|
|
31
|
-
* Exchange a valid refresh token for a new access + refresh token pair.
|
|
32
|
-
*
|
|
33
|
-
* Verifies the JWT, looks up the session in the database, checks expiry,
|
|
34
|
-
* then **rotates** the session: the old session is deleted and a new one is
|
|
35
|
-
* created. Old refresh tokens are immediately invalidated.
|
|
36
|
-
*/
|
|
37
|
-
refresh(refreshToken: string): Promise<RefreshResult<TRole>>;
|
|
38
|
-
/**
|
|
39
|
-
* Invalidate a single session identified by the refresh token.
|
|
40
|
-
*
|
|
41
|
-
* Safe to call even if the token is already expired — it will simply
|
|
42
|
-
* attempt a DB delete and resolve.
|
|
43
|
-
*/
|
|
44
|
-
logout(refreshToken: string): Promise<void>;
|
|
45
|
-
/**
|
|
46
|
-
* Delete all sessions for a user, effectively logging them out of every device.
|
|
47
|
-
*
|
|
48
|
-
* @param userId - The user's primary key as stored in the database.
|
|
49
|
-
*/
|
|
50
|
-
logoutAll(userId: string): Promise<void>;
|
|
51
|
-
/**
|
|
52
|
-
* Add roles to another user. Merges the given roles with the user's existing
|
|
53
|
-
* roles (no duplicates). The built-in router exposes this as
|
|
54
|
-
* `POST /users/:userId/roles` and restricts it to users with the `admin` role.
|
|
55
|
-
*/
|
|
56
|
-
assignRoles(userId: string, roles: string[]): Promise<AssignRolesResult<TRole>>;
|
|
57
14
|
/**
|
|
58
15
|
* Express middleware factory that enforces authentication.
|
|
59
16
|
*
|
|
@@ -77,36 +34,6 @@ export interface AuthClient<TRole extends string = string> {
|
|
|
77
34
|
* router.delete('/posts/:id', auth.protect(), auth.authorize('admin'), handler);
|
|
78
35
|
*/
|
|
79
36
|
authorize(...roles: TRole[]): RequestHandler;
|
|
80
|
-
/** Hash a plain-text password using the configured `saltRounds`. */
|
|
81
|
-
hashPassword(plain: string): Promise<string>;
|
|
82
|
-
/** Compare a plain-text password against a stored bcrypt hash. */
|
|
83
|
-
verifyPassword(plain: string, hash: string): Promise<boolean>;
|
|
84
|
-
/** Sign an access token for the given user payload. */
|
|
85
|
-
signAccessToken(payload: AuthUser<TRole>): string;
|
|
86
|
-
/** Sign a refresh token bound to a session ID. */
|
|
87
|
-
signRefreshToken(sessionId: string): string;
|
|
88
|
-
/** Verify and decode an access token. Throws `AuthError` if invalid or expired. */
|
|
89
|
-
verifyAccessToken(token: string): AuthUser<TRole>;
|
|
90
|
-
/** Verify and decode a refresh token. Throws `AuthError` if invalid or expired. */
|
|
91
|
-
verifyRefreshToken(token: string): {
|
|
92
|
-
sessionId: string;
|
|
93
|
-
};
|
|
94
|
-
/**
|
|
95
|
-
* Returns a pre-built Express Router with all standard auth endpoints mounted:
|
|
96
|
-
*
|
|
97
|
-
* - `POST /signup` — register, returns `{ user }`
|
|
98
|
-
* - `POST /login` — authenticate, sets refresh token cookie, returns `{ accessToken, user }`
|
|
99
|
-
* - `POST /refresh` — reads refresh token from cookie, returns `{ accessToken }`
|
|
100
|
-
* - `POST /logout` — invalidate current session
|
|
101
|
-
* - `POST /logout-all` — invalidate all sessions (requires valid access token)
|
|
102
|
-
*
|
|
103
|
-
* Requires `express.json()` to be applied before the router.
|
|
104
|
-
*
|
|
105
|
-
* @example
|
|
106
|
-
* app.use(express.json());
|
|
107
|
-
* app.use('/auth', auth.router());
|
|
108
|
-
*/
|
|
109
|
-
router(): Router;
|
|
110
37
|
/**
|
|
111
38
|
* Express middleware factory for resource-level permission checks.
|
|
112
39
|
*
|
|
@@ -140,6 +67,38 @@ export interface AuthClient<TRole extends string = string> {
|
|
|
140
67
|
*/
|
|
141
68
|
permit(check: PermitCheck): RequestHandler;
|
|
142
69
|
permit(options: PermitOptions<TRole>): RequestHandler;
|
|
70
|
+
/** Hash a plain-text password using the configured `saltRounds`. */
|
|
71
|
+
hashPassword(plain: string): Promise<string>;
|
|
72
|
+
/** Compare a plain-text password against a stored bcrypt hash. */
|
|
73
|
+
verifyPassword(plain: string, hash: string): Promise<boolean>;
|
|
74
|
+
/** Sign an access token for the given user payload. */
|
|
75
|
+
signAccessToken(payload: AuthUser<TRole>): string;
|
|
76
|
+
/** Sign a refresh token bound to a session ID. */
|
|
77
|
+
signRefreshToken(sessionId: string): string;
|
|
78
|
+
/** Verify and decode an access token. Throws `AuthError` if invalid or expired. */
|
|
79
|
+
verifyAccessToken(token: string): AuthUser<TRole>;
|
|
80
|
+
/** Verify and decode a refresh token. Throws `AuthError` if invalid or expired. */
|
|
81
|
+
verifyRefreshToken(token: string): {
|
|
82
|
+
sessionId: string;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Returns a pre-built Express Router with all standard auth endpoints mounted:
|
|
86
|
+
*
|
|
87
|
+
* - `POST /signup` — register a user, returns `{ user }`
|
|
88
|
+
* - `POST /login` — authenticate, sets refresh token cookie, returns `{ accessToken, user }`
|
|
89
|
+
* - `POST /refresh` — reads refresh token from cookie, returns `{ accessToken }`
|
|
90
|
+
* - `POST /logout` — invalidate current session
|
|
91
|
+
* - `POST /logout-all` — invalidate all sessions (requires valid access token)
|
|
92
|
+
* - `GET /me` — return the authenticated user
|
|
93
|
+
* - `POST /users/:userId/roles` — assign roles (requires admin)
|
|
94
|
+
*
|
|
95
|
+
* Requires `express.json()` to be applied before the router.
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* app.use(express.json());
|
|
99
|
+
* app.use('/auth', auth.router());
|
|
100
|
+
*/
|
|
101
|
+
router(): Router;
|
|
143
102
|
}
|
|
144
103
|
/**
|
|
145
104
|
* Create a fully configured auth client for your application.
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAEtD;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IACvD;;;;;;;;;;OAUG;IACH,OAAO,IAAI,cAAc,CAAC;IAE1B;;;;;;;;;OASG;IACH,SAAS,CAAC,GAAG,KAAK,EAAE,KAAK,EAAE,GAAG,cAAc,CAAC;IAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACH,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,cAAc,CAAC;IAC3C,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,cAAc,CAAC;IAEtD,oEAAoE;IACpE,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IAE7C,kEAAkE;IAClE,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE9D,uDAAuD;IACvD,eAAe,CAAC,OAAO,EAAE,QAAQ,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC;IAElD,kDAAkD;IAClD,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAE5C,mFAAmF;IACnF,iBAAiB,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAElD,mFAAmF;IACnF,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAEzD;;;;;;;;;;;;;;;;OAgBG;IACH,MAAM,IAAI,MAAM,CAAC;CAClB;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,UAAU,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,EACtD,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,GACxB,UAAU,CAAC,KAAK,CAAC,CAgBnB"}
|
package/dist/client.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { hashPassword, verifyPassword } from './libs/hash.js';
|
|
2
2
|
import { signAccessToken, signRefreshToken, verifyAccessToken, verifyRefreshToken } from './libs/token.js';
|
|
3
3
|
import { resolveConfig, validateConfig } from './libs/config.js';
|
|
4
|
-
import { signup, login, refresh, logout, logoutAll, assignRoles } from './services/auth.js';
|
|
5
4
|
import { protect } from './middleware/protect.js';
|
|
6
5
|
import { authorize } from './middleware/authorize.js';
|
|
7
6
|
import { permit } from './middleware/permit.js';
|
|
@@ -29,12 +28,6 @@ export function createAuth(config) {
|
|
|
29
28
|
validateConfig(config);
|
|
30
29
|
const resolved = resolveConfig(config);
|
|
31
30
|
return {
|
|
32
|
-
signup: (input) => signup(input, config),
|
|
33
|
-
login: (input) => login(input, config),
|
|
34
|
-
refresh: (refreshToken) => refresh(refreshToken, config),
|
|
35
|
-
logout: (refreshToken) => logout(refreshToken, config),
|
|
36
|
-
logoutAll: (userId) => logoutAll(userId, config),
|
|
37
|
-
assignRoles: (userId, roles) => assignRoles(userId, roles, config),
|
|
38
31
|
protect: () => protect(config),
|
|
39
32
|
authorize: (...roles) => authorize(...roles),
|
|
40
33
|
hashPassword: (plain) => hashPassword(plain, resolved.saltRounds),
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC3G,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAC3G,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AACjE,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAClD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAgH1D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,UAAU,CACxB,MAAyB;IAEzB,cAAc,CAAC,MAAoB,CAAC,CAAC;IACrC,MAAM,QAAQ,GAAG,aAAa,CAAC,MAAoB,CAAC,CAAC;IAErD,OAAO;QACL,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAoB,CAAC;QAC5C,SAAS,EAAE,CAAC,GAAG,KAAK,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC;QAC5C,YAAY,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,EAAE,QAAQ,CAAC,UAAU,CAAC;QACjE,cAAc,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,cAAc,CAAC,KAAK,EAAE,IAAI,CAAC;QAC5D,eAAe,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,eAAe,CAAC,OAAmB,EAAE,MAAoB,CAAC;QACxF,gBAAgB,EAAE,CAAC,SAAS,EAAE,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,MAAoB,CAAC;QAClF,iBAAiB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,iBAAiB,CAAC,KAAK,EAAE,MAAoB,CAAoB;QAC/F,kBAAkB,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,kBAAkB,CAAC,KAAK,EAAE,MAAoB,CAAC;QAC9E,MAAM,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,MAAM,CAAC;QACtC,MAAM,EAAE,CAAC,cAAkD,EAAE,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC;KACvF,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ declare global {
|
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
|
-
export type { AuthConfig, CookieConfig, AuthUser,
|
|
9
|
+
export type { AuthConfig, CookieConfig, AuthUser, ApiResponse, AuthAdapter, UserRecord, SessionRecord, CreateUserData, RouterHandlers, SignupInput, LoginInput, SignupResult, AuthResult, RefreshResult, AssignRolesResult, } from './types/auth.js';
|
|
10
10
|
export type { AuthErrorCode } from './errors/AuthError.js';
|
|
11
11
|
export type { AuthClient } from './client.js';
|
|
12
12
|
export { AuthError } from './errors/AuthError.js';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,IAAI,CAAC,EAAE,QAAQ,CAAC;SACjB;KACF;CACF;AAED,YAAY,EACV,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAIhD,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,OAAO,CAAC;QAChB,UAAU,OAAO;YACf,IAAI,CAAC,EAAE,QAAQ,CAAC;SACjB;KACF;CACF;AAED,YAAY,EACV,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,WAAW,EACX,WAAW,EACX,UAAU,EACV,aAAa,EACb,cAAc,EACd,cAAc,EACd,WAAW,EACX,UAAU,EACV,YAAY,EACZ,UAAU,EACV,aAAa,EACb,iBAAiB,GAClB,MAAM,iBAAiB,CAAC;AACzB,YAAY,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAC3D,YAAY,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAgCA,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC"}
|
package/dist/libs/config.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { AuthAdapter, AuthConfig } from '../types/auth.js';
|
|
2
|
+
/**
|
|
3
|
+
* Fully-resolved configuration with all optional fields filled in by
|
|
4
|
+
* their defaults. Produced by {@link resolveConfig} and used internally
|
|
5
|
+
* wherever the library needs guaranteed values.
|
|
6
|
+
*/
|
|
2
7
|
export interface ResolvedConfig {
|
|
3
8
|
secret: string;
|
|
4
9
|
accessExpiresIn: string | number;
|
|
@@ -9,10 +14,49 @@ export interface ResolvedConfig {
|
|
|
9
14
|
adapter: AuthAdapter;
|
|
10
15
|
}
|
|
11
16
|
/**
|
|
12
|
-
*
|
|
17
|
+
* Validate configuration at startup so misconfiguration is caught immediately,
|
|
13
18
|
* not at the first login attempt.
|
|
19
|
+
*
|
|
20
|
+
* Throws {@link AuthError} with code `CONFIGURATION_ERROR` for any of:
|
|
21
|
+
* - `secret` missing or shorter than 32 characters
|
|
22
|
+
* - `saltRounds` outside the range 10–31
|
|
23
|
+
* - `validRoles` is empty or missing
|
|
24
|
+
* - `adapter` is missing
|
|
25
|
+
*
|
|
26
|
+
* @param config - The raw config passed to {@link createAuth}.
|
|
27
|
+
* @throws {AuthError} With code `CONFIGURATION_ERROR` on any invalid field.
|
|
14
28
|
*/
|
|
15
29
|
export declare function validateConfig(config: AuthConfig): void;
|
|
30
|
+
/**
|
|
31
|
+
* Merge a partial {@link AuthConfig} with library defaults and return a
|
|
32
|
+
* fully-resolved configuration object.
|
|
33
|
+
*
|
|
34
|
+
* Does **not** validate the config — call {@link validateConfig} first.
|
|
35
|
+
*
|
|
36
|
+
* Defaults applied:
|
|
37
|
+
* - `accessExpiresIn` → `'15m'`
|
|
38
|
+
* - `refreshExpiresIn` → `'7d'`
|
|
39
|
+
* - `algorithm` → `'HS256'`
|
|
40
|
+
* - `saltRounds` → `12`
|
|
41
|
+
*
|
|
42
|
+
* @param partial - The raw config passed to {@link createAuth}.
|
|
43
|
+
* @returns A {@link ResolvedConfig} with every field guaranteed to be present.
|
|
44
|
+
*/
|
|
16
45
|
export declare function resolveConfig(partial: AuthConfig): ResolvedConfig;
|
|
46
|
+
/**
|
|
47
|
+
* Convert a duration string or a number of seconds into milliseconds.
|
|
48
|
+
*
|
|
49
|
+
* Supported unit suffixes: `s` (seconds), `m` (minutes), `h` (hours),
|
|
50
|
+
* `d` (days), `w` (weeks). Numeric inputs are treated as seconds.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* parseExpiry('15m') // 900_000
|
|
54
|
+
* parseExpiry('7d') // 604_800_000
|
|
55
|
+
* parseExpiry(60) // 60_000
|
|
56
|
+
*
|
|
57
|
+
* @param expiresIn - A duration string (e.g. `'15m'`, `'7d'`) or a number of seconds.
|
|
58
|
+
* @returns The equivalent duration in milliseconds.
|
|
59
|
+
* @throws {Error} If the string format is unrecognised.
|
|
60
|
+
*/
|
|
17
61
|
export declare function parseExpiry(expiresIn: string | number): number;
|
|
18
62
|
//# sourceMappingURL=config.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/libs/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEhE,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,OAAO,EAAE,WAAW,CAAC;CACtB;AAMD
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/libs/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEhE;;;;GAIG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,SAAS,EAAE,OAAO,GAAG,OAAO,GAAG,OAAO,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IAC9B,OAAO,EAAE,WAAW,CAAC;CACtB;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CA0BvD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,UAAU,GAAG,cAAc,CAUjE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAkB9D"}
|
package/dist/libs/config.js
CHANGED
|
@@ -3,8 +3,17 @@ const MIN_SECRET_LENGTH = 32;
|
|
|
3
3
|
const MIN_SALT_ROUNDS = 10;
|
|
4
4
|
const MAX_SALT_ROUNDS = 31;
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Validate configuration at startup so misconfiguration is caught immediately,
|
|
7
7
|
* not at the first login attempt.
|
|
8
|
+
*
|
|
9
|
+
* Throws {@link AuthError} with code `CONFIGURATION_ERROR` for any of:
|
|
10
|
+
* - `secret` missing or shorter than 32 characters
|
|
11
|
+
* - `saltRounds` outside the range 10–31
|
|
12
|
+
* - `validRoles` is empty or missing
|
|
13
|
+
* - `adapter` is missing
|
|
14
|
+
*
|
|
15
|
+
* @param config - The raw config passed to {@link createAuth}.
|
|
16
|
+
* @throws {AuthError} With code `CONFIGURATION_ERROR` on any invalid field.
|
|
8
17
|
*/
|
|
9
18
|
export function validateConfig(config) {
|
|
10
19
|
if (!config.secret || config.secret.trim().length === 0) {
|
|
@@ -24,6 +33,21 @@ export function validateConfig(config) {
|
|
|
24
33
|
throw new AuthError('CONFIGURATION_ERROR', 'adapter is required');
|
|
25
34
|
}
|
|
26
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Merge a partial {@link AuthConfig} with library defaults and return a
|
|
38
|
+
* fully-resolved configuration object.
|
|
39
|
+
*
|
|
40
|
+
* Does **not** validate the config — call {@link validateConfig} first.
|
|
41
|
+
*
|
|
42
|
+
* Defaults applied:
|
|
43
|
+
* - `accessExpiresIn` → `'15m'`
|
|
44
|
+
* - `refreshExpiresIn` → `'7d'`
|
|
45
|
+
* - `algorithm` → `'HS256'`
|
|
46
|
+
* - `saltRounds` → `12`
|
|
47
|
+
*
|
|
48
|
+
* @param partial - The raw config passed to {@link createAuth}.
|
|
49
|
+
* @returns A {@link ResolvedConfig} with every field guaranteed to be present.
|
|
50
|
+
*/
|
|
27
51
|
export function resolveConfig(partial) {
|
|
28
52
|
return {
|
|
29
53
|
secret: partial.secret,
|
|
@@ -35,7 +59,21 @@ export function resolveConfig(partial) {
|
|
|
35
59
|
adapter: partial.adapter,
|
|
36
60
|
};
|
|
37
61
|
}
|
|
38
|
-
|
|
62
|
+
/**
|
|
63
|
+
* Convert a duration string or a number of seconds into milliseconds.
|
|
64
|
+
*
|
|
65
|
+
* Supported unit suffixes: `s` (seconds), `m` (minutes), `h` (hours),
|
|
66
|
+
* `d` (days), `w` (weeks). Numeric inputs are treated as seconds.
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* parseExpiry('15m') // 900_000
|
|
70
|
+
* parseExpiry('7d') // 604_800_000
|
|
71
|
+
* parseExpiry(60) // 60_000
|
|
72
|
+
*
|
|
73
|
+
* @param expiresIn - A duration string (e.g. `'15m'`, `'7d'`) or a number of seconds.
|
|
74
|
+
* @returns The equivalent duration in milliseconds.
|
|
75
|
+
* @throws {Error} If the string format is unrecognised.
|
|
76
|
+
*/
|
|
39
77
|
export function parseExpiry(expiresIn) {
|
|
40
78
|
if (typeof expiresIn === 'number')
|
|
41
79
|
return expiresIn * 1000;
|
package/dist/libs/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/libs/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/libs/config.ts"],"names":[],"mappings":"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"}
|
package/dist/libs/hash.d.ts
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hash a plain-text password using bcrypt.
|
|
3
|
+
*
|
|
4
|
+
* @param plain - The raw password string supplied by the user.
|
|
5
|
+
* @param saltRounds - bcrypt cost factor; higher values increase security at the cost of speed.
|
|
6
|
+
* @returns The bcrypt hash string to persist in the database.
|
|
7
|
+
*/
|
|
1
8
|
export declare function hashPassword(plain: string, saltRounds?: number): Promise<string>;
|
|
9
|
+
/**
|
|
10
|
+
* Compare a plain-text password against a stored bcrypt hash.
|
|
11
|
+
*
|
|
12
|
+
* @param plain - The raw password string to verify.
|
|
13
|
+
* @param hash - The stored bcrypt hash from the database.
|
|
14
|
+
* @returns `true` if the password matches the hash, `false` otherwise.
|
|
15
|
+
*/
|
|
2
16
|
export declare function verifyPassword(plain: string, hash: string): Promise<boolean>;
|
|
3
17
|
//# sourceMappingURL=hash.d.ts.map
|
package/dist/libs/hash.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/libs/hash.ts"],"names":[],"mappings":"AAEA,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,SAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAElF;AAED,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAElF"}
|
|
1
|
+
{"version":3,"file":"hash.d.ts","sourceRoot":"","sources":["../../src/libs/hash.ts"],"names":[],"mappings":"AAEA;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,SAAK,GAAG,OAAO,CAAC,MAAM,CAAC,CAElF;AAED;;;;;;GAMG;AACH,wBAAsB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAElF"}
|
package/dist/libs/hash.js
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
import bcrypt from 'bcrypt';
|
|
2
|
+
/**
|
|
3
|
+
* Hash a plain-text password using bcrypt.
|
|
4
|
+
*
|
|
5
|
+
* @param plain - The raw password string supplied by the user.
|
|
6
|
+
* @param saltRounds - bcrypt cost factor; higher values increase security at the cost of speed.
|
|
7
|
+
* @returns The bcrypt hash string to persist in the database.
|
|
8
|
+
*/
|
|
2
9
|
export async function hashPassword(plain, saltRounds = 12) {
|
|
3
10
|
return bcrypt.hash(plain, saltRounds);
|
|
4
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Compare a plain-text password against a stored bcrypt hash.
|
|
14
|
+
*
|
|
15
|
+
* @param plain - The raw password string to verify.
|
|
16
|
+
* @param hash - The stored bcrypt hash from the database.
|
|
17
|
+
* @returns `true` if the password matches the hash, `false` otherwise.
|
|
18
|
+
*/
|
|
5
19
|
export async function verifyPassword(plain, hash) {
|
|
6
20
|
return bcrypt.compare(plain, hash);
|
|
7
21
|
}
|
package/dist/libs/hash.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/libs/hash.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAa,EAAE,UAAU,GAAG,EAAE;IAC/D,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAa,EAAE,IAAY;IAC9D,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC"}
|
|
1
|
+
{"version":3,"file":"hash.js","sourceRoot":"","sources":["../../src/libs/hash.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,KAAa,EAAE,UAAU,GAAG,EAAE;IAC/D,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,KAAa,EAAE,IAAY;IAC9D,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC"}
|
package/dist/libs/token.d.ts
CHANGED
|
@@ -1,7 +1,44 @@
|
|
|
1
1
|
import type { AuthConfig, AuthUser } from '../types/auth.js';
|
|
2
|
+
/**
|
|
3
|
+
* Sign a short-lived access token containing the user's identity and roles.
|
|
4
|
+
*
|
|
5
|
+
* Uses the access-specific secret derived from config and the configured
|
|
6
|
+
* `accessExpiresIn` duration and HMAC algorithm.
|
|
7
|
+
*
|
|
8
|
+
* @param payload - The {@link AuthUser} payload to embed (id, identifier, roles).
|
|
9
|
+
* @param config - Auth configuration used to derive the secret and options.
|
|
10
|
+
* @returns Compact JWT string.
|
|
11
|
+
*/
|
|
2
12
|
export declare function signAccessToken(payload: AuthUser, config: AuthConfig): string;
|
|
13
|
+
/**
|
|
14
|
+
* Sign a long-lived refresh token bound to a specific session ID.
|
|
15
|
+
*
|
|
16
|
+
* Uses the refresh-specific secret derived from config and the configured
|
|
17
|
+
* `refreshExpiresIn` duration. The session ID is embedded as the sole claim
|
|
18
|
+
* so the token can be used to look up and rotate the session.
|
|
19
|
+
*
|
|
20
|
+
* @param sessionId - The database session ID to bind to this token.
|
|
21
|
+
* @param config - Auth configuration used to derive the secret and options.
|
|
22
|
+
* @returns Compact JWT string.
|
|
23
|
+
*/
|
|
3
24
|
export declare function signRefreshToken(sessionId: string, config: AuthConfig): string;
|
|
25
|
+
/**
|
|
26
|
+
* Verify an access token and return its decoded {@link AuthUser} payload.
|
|
27
|
+
*
|
|
28
|
+
* @param token - Compact JWT access token string.
|
|
29
|
+
* @param config - Auth configuration used to derive the secret and algorithm.
|
|
30
|
+
* @returns Decoded `AuthUser` payload (id, identifier, roles).
|
|
31
|
+
* @throws {AuthError} With `TOKEN_EXPIRED` if expired, `TOKEN_INVALID` otherwise.
|
|
32
|
+
*/
|
|
4
33
|
export declare function verifyAccessToken(token: string, config: AuthConfig): AuthUser;
|
|
34
|
+
/**
|
|
35
|
+
* Verify a refresh token and return the embedded session ID.
|
|
36
|
+
*
|
|
37
|
+
* @param token - Compact JWT refresh token string.
|
|
38
|
+
* @param config - Auth configuration used to derive the secret and algorithm.
|
|
39
|
+
* @returns Object with `sessionId` matching the one passed to {@link signRefreshToken}.
|
|
40
|
+
* @throws {AuthError} With `TOKEN_EXPIRED` if expired, `TOKEN_INVALID` otherwise.
|
|
41
|
+
*/
|
|
5
42
|
export declare function verifyRefreshToken(token: string, config: AuthConfig): {
|
|
6
43
|
sessionId: string;
|
|
7
44
|
};
|
package/dist/libs/token.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../src/libs/token.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"token.d.ts","sourceRoot":"","sources":["../../src/libs/token.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAqE7D;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAI7E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAI9E;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,QAAQ,CAI7E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG;IAAE,SAAS,EAAE,MAAM,CAAA;CAAE,CAI3F"}
|