sentri 1.0.5 → 1.1.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 +182 -46
- package/dist/client.d.ts +43 -82
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +0 -7
- package/dist/client.js.map +1 -1
- package/dist/errors/AuthError.d.ts +9 -8
- package/dist/errors/AuthError.d.ts.map +1 -1
- package/dist/errors/AuthError.js +9 -8
- package/dist/errors/AuthError.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 +40 -2
- package/dist/libs/token.d.ts.map +1 -1
- package/dist/libs/token.js +64 -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 +27 -0
- package/dist/middleware/protect.d.ts.map +1 -1
- package/dist/middleware/protect.js +37 -2
- package/dist/middleware/protect.js.map +1 -1
- package/dist/middleware/router.d.ts +13 -6
- package/dist/middleware/router.d.ts.map +1 -1
- package/dist/middleware/router.js +49 -15
- package/dist/middleware/router.js.map +1 -1
- package/dist/services/auth.d.ts +77 -0
- package/dist/services/auth.d.ts.map +1 -1
- package/dist/services/auth.js +81 -2
- package/dist/services/auth.js.map +1 -1
- package/dist/types/auth.d.ts +189 -3
- package/dist/types/auth.d.ts.map +1 -1
- package/dist/types/auth.js.map +1 -1
- package/package.json +15 -4
- 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
|
@@ -56,18 +56,31 @@ function clearCookie(response, config) {
|
|
|
56
56
|
const cookieConfig = config.cookie ?? {};
|
|
57
57
|
response.clearCookie(getCookieName(config), { path: cookieConfig.path ?? '/' });
|
|
58
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Validate the `X-Api-Key` header when `config.apiKey` is set.
|
|
61
|
+
* Throws `AuthError` with code `UNAUTHORIZED` on mismatch.
|
|
62
|
+
*/
|
|
63
|
+
function validateApiKey(request, config) {
|
|
64
|
+
if (!config.apiKey)
|
|
65
|
+
return;
|
|
66
|
+
const provided = request.headers['x-api-key'];
|
|
67
|
+
if (typeof provided !== 'string' || provided !== config.apiKey) {
|
|
68
|
+
throw new AuthError('UNAUTHORIZED', 'Invalid or missing API key');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
59
71
|
/**
|
|
60
72
|
* Creates a pre-built Express Router with all standard auth endpoints.
|
|
61
73
|
*
|
|
62
74
|
* Mount it once and all routes are ready:
|
|
63
75
|
*
|
|
64
76
|
* ```
|
|
65
|
-
* POST /
|
|
66
|
-
* POST /login
|
|
67
|
-
* POST /refresh
|
|
68
|
-
* POST /logout
|
|
69
|
-
* POST /logout-all
|
|
70
|
-
* GET /me
|
|
77
|
+
* POST /register — register a new user (protected by X-Api-Key when config.apiKey is set)
|
|
78
|
+
* POST /login — authenticate and get tokens
|
|
79
|
+
* POST /refresh — rotate refresh token
|
|
80
|
+
* POST /logout — invalidate current session; access tokens issued before logout become invalid
|
|
81
|
+
* POST /logout-all — invalidate all sessions for the authenticated user
|
|
82
|
+
* GET /me — return the currently authenticated user
|
|
83
|
+
* POST /users/:userId/roles — assign roles (admin only)
|
|
71
84
|
* ```
|
|
72
85
|
*
|
|
73
86
|
* Requires `express.json()` to be applied before the router.
|
|
@@ -75,14 +88,37 @@ function clearCookie(response, config) {
|
|
|
75
88
|
* When `cookie` is set in config, the refresh token is stored in an httpOnly
|
|
76
89
|
* cookie automatically — no `cookie-parser` needed.
|
|
77
90
|
*
|
|
91
|
+
* When `apiKey` is set in config, `POST /register` requires the caller to send
|
|
92
|
+
* an `X-Api-Key: <key>` header matching the configured value.
|
|
93
|
+
*
|
|
94
|
+
* When `router` is set in config, individual service functions can be replaced
|
|
95
|
+
* while the router still handles validation and response formatting.
|
|
96
|
+
*
|
|
78
97
|
* @example
|
|
79
98
|
* app.use(express.json());
|
|
80
99
|
* app.use('/auth', auth.router());
|
|
81
100
|
*/
|
|
82
101
|
export function createAuthRouter(config) {
|
|
83
102
|
const router = Router();
|
|
84
|
-
router
|
|
103
|
+
// Resolve service functions — use custom override from config.router when provided, else fall back to the built-in service.
|
|
104
|
+
const baseConfig = config;
|
|
105
|
+
const registerFn = config.router?.register ?? ((input) => signup(input, baseConfig));
|
|
106
|
+
const loginFn = config.router?.login ?? ((input) => login(input, baseConfig));
|
|
107
|
+
const refreshFn = config.router?.refresh ?? ((token) => refresh(token, baseConfig));
|
|
108
|
+
const logoutFn = config.router?.logout ?? ((token) => token !== undefined ? logout(token, baseConfig) : Promise.resolve());
|
|
109
|
+
const logoutAllFn = config.router?.logoutAll ?? ((userId) => logoutAll(userId, baseConfig));
|
|
110
|
+
const assignRolesFn = config.router?.assignRoles ?? ((userId, roles) => assignRoles(userId, roles, baseConfig));
|
|
111
|
+
/**
|
|
112
|
+
* POST /register
|
|
113
|
+
*
|
|
114
|
+
* Register a new user. Does **not** issue tokens — call `/login` after registration.
|
|
115
|
+
*
|
|
116
|
+
* When `config.apiKey` is set the caller must supply the matching value in the
|
|
117
|
+
* `X-Api-Key` header, preventing arbitrary users from self-registering as admins.
|
|
118
|
+
*/
|
|
119
|
+
router.post('/register', async (request, response, next) => {
|
|
85
120
|
try {
|
|
121
|
+
validateApiKey(request, config);
|
|
86
122
|
const body = parseBody(request.body);
|
|
87
123
|
const { identifier, password, roles } = body;
|
|
88
124
|
if (typeof identifier !== 'string' || identifier.trim().length === 0) {
|
|
@@ -107,7 +143,7 @@ export function createAuthRouter(config) {
|
|
|
107
143
|
const input = rolesInput !== undefined
|
|
108
144
|
? { identifier: identifier.trim(), password, roles: rolesInput }
|
|
109
145
|
: { identifier: identifier.trim(), password };
|
|
110
|
-
const result = await
|
|
146
|
+
const result = await registerFn(input);
|
|
111
147
|
if (!result.success) {
|
|
112
148
|
fail(response, result.error);
|
|
113
149
|
return;
|
|
@@ -134,7 +170,7 @@ export function createAuthRouter(config) {
|
|
|
134
170
|
if (password.length > MAX_PASSWORD_LENGTH) {
|
|
135
171
|
throw badRequest(`password must not exceed ${MAX_PASSWORD_LENGTH} characters`);
|
|
136
172
|
}
|
|
137
|
-
const result = await
|
|
173
|
+
const result = await loginFn({ identifier: identifier.trim(), password });
|
|
138
174
|
if (!result.success) {
|
|
139
175
|
fail(response, result.error);
|
|
140
176
|
return;
|
|
@@ -152,7 +188,7 @@ export function createAuthRouter(config) {
|
|
|
152
188
|
if (!fromCookie) {
|
|
153
189
|
throw new AuthError('UNAUTHORIZED', 'Refresh token cookie is missing');
|
|
154
190
|
}
|
|
155
|
-
const result = await
|
|
191
|
+
const result = await refreshFn(fromCookie);
|
|
156
192
|
if (!result.success) {
|
|
157
193
|
clearCookie(response, config);
|
|
158
194
|
fail(response, result.error);
|
|
@@ -168,9 +204,7 @@ export function createAuthRouter(config) {
|
|
|
168
204
|
router.post('/logout', async (request, response, next) => {
|
|
169
205
|
try {
|
|
170
206
|
const fromCookie = readCookie(request.headers['cookie'], getCookieName(config));
|
|
171
|
-
|
|
172
|
-
await logout(fromCookie, config);
|
|
173
|
-
}
|
|
207
|
+
await logoutFn(fromCookie);
|
|
174
208
|
clearCookie(response, config);
|
|
175
209
|
ok(response, 200, 'Logged out', null);
|
|
176
210
|
}
|
|
@@ -180,7 +214,7 @@ export function createAuthRouter(config) {
|
|
|
180
214
|
});
|
|
181
215
|
router.post('/logout-all', protect(config), async (request, response, next) => {
|
|
182
216
|
try {
|
|
183
|
-
await
|
|
217
|
+
await logoutAllFn(request.user.id);
|
|
184
218
|
clearCookie(response, config);
|
|
185
219
|
ok(response, 200, 'All sessions revoked', null);
|
|
186
220
|
}
|
|
@@ -206,7 +240,7 @@ export function createAuthRouter(config) {
|
|
|
206
240
|
if (!roles.every((role) => typeof role === 'string')) {
|
|
207
241
|
throw badRequest('each role must be a string');
|
|
208
242
|
}
|
|
209
|
-
const result = await
|
|
243
|
+
const result = await assignRolesFn(userId, roles);
|
|
210
244
|
if (!result.success) {
|
|
211
245
|
fail(response, result.error);
|
|
212
246
|
return;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/middleware/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAkD,MAAM,SAAS,CAAC;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/middleware/router.ts"],"names":[],"mappings":"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"}
|
package/dist/services/auth.d.ts
CHANGED
|
@@ -1,8 +1,85 @@
|
|
|
1
1
|
import type { AssignRolesResult, AuthConfig, AuthResult, LoginInput, RefreshResult, SignupInput, SignupResult } from '../types/auth.js';
|
|
2
|
+
/**
|
|
3
|
+
* Register a new user.
|
|
4
|
+
*
|
|
5
|
+
* Validates that every requested role is in `validRoles`, rejects duplicate
|
|
6
|
+
* identifiers, hashes the password with bcrypt, creates the user record via
|
|
7
|
+
* the adapter, and returns the created user.
|
|
8
|
+
*
|
|
9
|
+
* No tokens are issued — the caller should invoke `login` after signup if
|
|
10
|
+
* immediate authentication is desired.
|
|
11
|
+
*
|
|
12
|
+
* @param input - Signup data: identifier, plain-text password, and optional roles.
|
|
13
|
+
* @param config - Auth configuration containing the adapter and role definitions.
|
|
14
|
+
* @returns `{ success: true, user }` on success, or `{ success: false, error }` with
|
|
15
|
+
* code `INVALID_ROLE` or `USER_ALREADY_EXISTS` on failure.
|
|
16
|
+
*/
|
|
2
17
|
export declare function signup(input: SignupInput, config: AuthConfig): Promise<SignupResult>;
|
|
18
|
+
/**
|
|
19
|
+
* Authenticate an existing user by identifier and plain-text password.
|
|
20
|
+
*
|
|
21
|
+
* Looks up the user, verifies the password with bcrypt, creates a new session,
|
|
22
|
+
* and issues a JWT access token + refresh token pair. The access token embeds
|
|
23
|
+
* the session ID so that `protect()` can reject it immediately after logout
|
|
24
|
+
* without waiting for the token to expire.
|
|
25
|
+
*
|
|
26
|
+
* The failure response always uses code `INVALID_CREDENTIALS` regardless of
|
|
27
|
+
* whether the identifier or the password was wrong, preventing user enumeration.
|
|
28
|
+
*
|
|
29
|
+
* @param input - Login data: identifier and plain-text password.
|
|
30
|
+
* @param config - Auth configuration containing the adapter and JWT settings.
|
|
31
|
+
* @returns `{ success: true, accessToken, refreshToken, user }` on success, or
|
|
32
|
+
* `{ success: false, error }` with code `INVALID_CREDENTIALS` on failure.
|
|
33
|
+
*/
|
|
3
34
|
export declare function login(input: LoginInput, config: AuthConfig): Promise<AuthResult>;
|
|
35
|
+
/**
|
|
36
|
+
* Exchange a valid refresh token for a new access + refresh token pair.
|
|
37
|
+
*
|
|
38
|
+
* Implements **session rotation**: the old session is deleted and a fresh
|
|
39
|
+
* session is created, so each refresh token is single-use. An attacker
|
|
40
|
+
* replaying a stolen refresh token after it has already been rotated will
|
|
41
|
+
* find the session gone.
|
|
42
|
+
*
|
|
43
|
+
* @param refreshToken - The JWT refresh token (typically from an httpOnly cookie).
|
|
44
|
+
* @param config - Auth configuration containing the adapter and JWT settings.
|
|
45
|
+
* @returns `{ success: true, accessToken, refreshToken, user }` on success, or
|
|
46
|
+
* `{ success: false, error }` with code `UNAUTHORIZED`, `TOKEN_EXPIRED`, or
|
|
47
|
+
* `TOKEN_INVALID` on failure.
|
|
48
|
+
*/
|
|
4
49
|
export declare function refresh(refreshToken: string, config: AuthConfig): Promise<RefreshResult>;
|
|
50
|
+
/**
|
|
51
|
+
* Invalidate a single session identified by a refresh token.
|
|
52
|
+
*
|
|
53
|
+
* Safe to call even when the token is already expired or invalid — the JWT
|
|
54
|
+
* parse failure is silently swallowed and the function resolves normally.
|
|
55
|
+
* This makes logout idempotent from the client's perspective.
|
|
56
|
+
*
|
|
57
|
+
* @param refreshToken - The JWT refresh token bound to the session to revoke.
|
|
58
|
+
* @param config - Auth configuration containing the adapter and JWT settings.
|
|
59
|
+
*/
|
|
5
60
|
export declare function logout(refreshToken: string, config: AuthConfig): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Delete all sessions for a user, effectively logging them out of every device.
|
|
63
|
+
*
|
|
64
|
+
* Delegates to `adapter.session.deleteAllForUser`. No token is required — the
|
|
65
|
+
* router route that calls this function is already guarded by `protect()`.
|
|
66
|
+
*
|
|
67
|
+
* @param userId - The user's primary key as stored in the database.
|
|
68
|
+
* @param config - Auth configuration containing the adapter.
|
|
69
|
+
*/
|
|
6
70
|
export declare function logoutAll(userId: string, config: AuthConfig): Promise<void>;
|
|
71
|
+
/**
|
|
72
|
+
* Add roles to a user account, merging them with any existing roles.
|
|
73
|
+
*
|
|
74
|
+
* Validates that every role in `rolesToAdd` is listed in `config.validRoles`.
|
|
75
|
+
* The resulting role set is deduplicated before being persisted via
|
|
76
|
+
* `adapter.user.updateRoles`.
|
|
77
|
+
*
|
|
78
|
+
* @param userId - The primary key of the user to update.
|
|
79
|
+
* @param rolesToAdd - Role names to assign. Must all be present in `validRoles`.
|
|
80
|
+
* @param config - Auth configuration containing the adapter and role definitions.
|
|
81
|
+
* @returns `{ success: true, user }` on success, or `{ success: false, error }` with
|
|
82
|
+
* code `INVALID_ROLE` or `USER_NOT_FOUND` on failure.
|
|
83
|
+
*/
|
|
7
84
|
export declare function assignRoles(userId: string, rolesToAdd: string[], config: AuthConfig): Promise<AssignRolesResult>;
|
|
8
85
|
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/services/auth.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAExI,wBAAsB,MAAM,CAC1B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,YAAY,CAAC,CAoBvB;AAED,wBAAsB,KAAK,CACzB,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,UAAU,CAAC,
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/services/auth.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAExI;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,MAAM,CAC1B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,YAAY,CAAC,CAoBvB;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,KAAK,CACzB,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,UAAU,CAAC,CAqBrB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,OAAO,CAC3B,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,aAAa,CAAC,CA+BxB;AAED;;;;;;;;;GASG;AACH,wBAAsB,MAAM,CAC1B,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;;;;;;GAQG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,IAAI,CAAC,CAEf;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,UAAU,EAAE,MAAM,EAAE,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,iBAAiB,CAAC,CAiB5B"}
|
package/dist/services/auth.js
CHANGED
|
@@ -2,6 +2,21 @@ import { AuthError } from '../errors/AuthError.js';
|
|
|
2
2
|
import { hashPassword, verifyPassword } from '../libs/hash.js';
|
|
3
3
|
import { signAccessToken, signRefreshToken, verifyRefreshToken } from '../libs/token.js';
|
|
4
4
|
import { resolveConfig, parseExpiry } from '../libs/config.js';
|
|
5
|
+
/**
|
|
6
|
+
* Register a new user.
|
|
7
|
+
*
|
|
8
|
+
* Validates that every requested role is in `validRoles`, rejects duplicate
|
|
9
|
+
* identifiers, hashes the password with bcrypt, creates the user record via
|
|
10
|
+
* the adapter, and returns the created user.
|
|
11
|
+
*
|
|
12
|
+
* No tokens are issued — the caller should invoke `login` after signup if
|
|
13
|
+
* immediate authentication is desired.
|
|
14
|
+
*
|
|
15
|
+
* @param input - Signup data: identifier, plain-text password, and optional roles.
|
|
16
|
+
* @param config - Auth configuration containing the adapter and role definitions.
|
|
17
|
+
* @returns `{ success: true, user }` on success, or `{ success: false, error }` with
|
|
18
|
+
* code `INVALID_ROLE` or `USER_ALREADY_EXISTS` on failure.
|
|
19
|
+
*/
|
|
5
20
|
export async function signup(input, config) {
|
|
6
21
|
const resolved = resolveConfig(config);
|
|
7
22
|
const requestedRoles = input.roles ?? [];
|
|
@@ -19,6 +34,22 @@ export async function signup(input, config) {
|
|
|
19
34
|
const user = { id: created.id, identifier, roles: requestedRoles };
|
|
20
35
|
return { success: true, user };
|
|
21
36
|
}
|
|
37
|
+
/**
|
|
38
|
+
* Authenticate an existing user by identifier and plain-text password.
|
|
39
|
+
*
|
|
40
|
+
* Looks up the user, verifies the password with bcrypt, creates a new session,
|
|
41
|
+
* and issues a JWT access token + refresh token pair. The access token embeds
|
|
42
|
+
* the session ID so that `protect()` can reject it immediately after logout
|
|
43
|
+
* without waiting for the token to expire.
|
|
44
|
+
*
|
|
45
|
+
* The failure response always uses code `INVALID_CREDENTIALS` regardless of
|
|
46
|
+
* whether the identifier or the password was wrong, preventing user enumeration.
|
|
47
|
+
*
|
|
48
|
+
* @param input - Login data: identifier and plain-text password.
|
|
49
|
+
* @param config - Auth configuration containing the adapter and JWT settings.
|
|
50
|
+
* @returns `{ success: true, accessToken, refreshToken, user }` on success, or
|
|
51
|
+
* `{ success: false, error }` with code `INVALID_CREDENTIALS` on failure.
|
|
52
|
+
*/
|
|
22
53
|
export async function login(input, config) {
|
|
23
54
|
const resolved = resolveConfig(config);
|
|
24
55
|
const found = await resolved.adapter.user.findByIdentifier(input.identifier.trim());
|
|
@@ -32,10 +63,25 @@ export async function login(input, config) {
|
|
|
32
63
|
const expiresAt = new Date(Date.now() + parseExpiry(resolved.refreshExpiresIn));
|
|
33
64
|
const session = await resolved.adapter.session.create({ userId: found.id, expiresAt });
|
|
34
65
|
const user = { id: found.id, identifier: found.identifier, roles: found.roles };
|
|
35
|
-
|
|
66
|
+
// Embed sessionId in the access token so protect() can invalidate it on logout.
|
|
67
|
+
const accessToken = signAccessToken({ ...user, sessionId: session.id }, config);
|
|
36
68
|
const refreshToken = signRefreshToken(session.id, config);
|
|
37
69
|
return { success: true, accessToken, refreshToken, user };
|
|
38
70
|
}
|
|
71
|
+
/**
|
|
72
|
+
* Exchange a valid refresh token for a new access + refresh token pair.
|
|
73
|
+
*
|
|
74
|
+
* Implements **session rotation**: the old session is deleted and a fresh
|
|
75
|
+
* session is created, so each refresh token is single-use. An attacker
|
|
76
|
+
* replaying a stolen refresh token after it has already been rotated will
|
|
77
|
+
* find the session gone.
|
|
78
|
+
*
|
|
79
|
+
* @param refreshToken - The JWT refresh token (typically from an httpOnly cookie).
|
|
80
|
+
* @param config - Auth configuration containing the adapter and JWT settings.
|
|
81
|
+
* @returns `{ success: true, accessToken, refreshToken, user }` on success, or
|
|
82
|
+
* `{ success: false, error }` with code `UNAUTHORIZED`, `TOKEN_EXPIRED`, or
|
|
83
|
+
* `TOKEN_INVALID` on failure.
|
|
84
|
+
*/
|
|
39
85
|
export async function refresh(refreshToken, config) {
|
|
40
86
|
const resolved = resolveConfig(config);
|
|
41
87
|
let sessionId;
|
|
@@ -60,10 +106,21 @@ export async function refresh(refreshToken, config) {
|
|
|
60
106
|
const expiresAt = new Date(Date.now() + parseExpiry(resolved.refreshExpiresIn));
|
|
61
107
|
const newSession = await resolved.adapter.session.create({ userId: session.userId, expiresAt });
|
|
62
108
|
const user = { id: session.user.id, identifier: session.user.identifier, roles: session.user.roles };
|
|
63
|
-
|
|
109
|
+
// Embed new sessionId in the rotated access token.
|
|
110
|
+
const newAccessToken = signAccessToken({ ...user, sessionId: newSession.id }, config);
|
|
64
111
|
const newRefreshToken = signRefreshToken(newSession.id, config);
|
|
65
112
|
return { success: true, accessToken: newAccessToken, refreshToken: newRefreshToken, user };
|
|
66
113
|
}
|
|
114
|
+
/**
|
|
115
|
+
* Invalidate a single session identified by a refresh token.
|
|
116
|
+
*
|
|
117
|
+
* Safe to call even when the token is already expired or invalid — the JWT
|
|
118
|
+
* parse failure is silently swallowed and the function resolves normally.
|
|
119
|
+
* This makes logout idempotent from the client's perspective.
|
|
120
|
+
*
|
|
121
|
+
* @param refreshToken - The JWT refresh token bound to the session to revoke.
|
|
122
|
+
* @param config - Auth configuration containing the adapter and JWT settings.
|
|
123
|
+
*/
|
|
67
124
|
export async function logout(refreshToken, config) {
|
|
68
125
|
let sessionId;
|
|
69
126
|
try {
|
|
@@ -74,9 +131,31 @@ export async function logout(refreshToken, config) {
|
|
|
74
131
|
}
|
|
75
132
|
await resolveConfig(config).adapter.session.delete(sessionId);
|
|
76
133
|
}
|
|
134
|
+
/**
|
|
135
|
+
* Delete all sessions for a user, effectively logging them out of every device.
|
|
136
|
+
*
|
|
137
|
+
* Delegates to `adapter.session.deleteAllForUser`. No token is required — the
|
|
138
|
+
* router route that calls this function is already guarded by `protect()`.
|
|
139
|
+
*
|
|
140
|
+
* @param userId - The user's primary key as stored in the database.
|
|
141
|
+
* @param config - Auth configuration containing the adapter.
|
|
142
|
+
*/
|
|
77
143
|
export async function logoutAll(userId, config) {
|
|
78
144
|
await resolveConfig(config).adapter.session.deleteAllForUser(userId);
|
|
79
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Add roles to a user account, merging them with any existing roles.
|
|
148
|
+
*
|
|
149
|
+
* Validates that every role in `rolesToAdd` is listed in `config.validRoles`.
|
|
150
|
+
* The resulting role set is deduplicated before being persisted via
|
|
151
|
+
* `adapter.user.updateRoles`.
|
|
152
|
+
*
|
|
153
|
+
* @param userId - The primary key of the user to update.
|
|
154
|
+
* @param rolesToAdd - Role names to assign. Must all be present in `validRoles`.
|
|
155
|
+
* @param config - Auth configuration containing the adapter and role definitions.
|
|
156
|
+
* @returns `{ success: true, user }` on success, or `{ success: false, error }` with
|
|
157
|
+
* code `INVALID_ROLE` or `USER_NOT_FOUND` on failure.
|
|
158
|
+
*/
|
|
80
159
|
export async function assignRoles(userId, rolesToAdd, config) {
|
|
81
160
|
const resolved = resolveConfig(config);
|
|
82
161
|
const invalidRoles = rolesToAdd.filter((role) => !resolved.validRoles.includes(role));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/services/auth.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/services/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/types/auth.d.ts
CHANGED
|
@@ -7,6 +7,14 @@ export interface ApiResponse<T = null> {
|
|
|
7
7
|
message: string;
|
|
8
8
|
data: T | null;
|
|
9
9
|
}
|
|
10
|
+
/**
|
|
11
|
+
* @internal Extended JWT payload decoded from an access token.
|
|
12
|
+
* Includes `sessionId` which is not exposed on `req.user` but is used
|
|
13
|
+
* by `protect()` to validate that the session is still active.
|
|
14
|
+
*/
|
|
15
|
+
export interface AccessTokenPayload<TRole extends string = string> extends AuthUser<TRole> {
|
|
16
|
+
sessionId: string;
|
|
17
|
+
}
|
|
10
18
|
/** Maps an {@link AuthErrorCode} to its corresponding HTTP status code. */
|
|
11
19
|
export declare function authErrorStatus(code: AuthErrorCode): number;
|
|
12
20
|
/** Shape of a user row returned by the adapter — used internally by the library. */
|
|
@@ -97,6 +105,132 @@ export interface AuthAdapter {
|
|
|
97
105
|
deleteAllForUser(userId: string): Promise<void>;
|
|
98
106
|
};
|
|
99
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Custom service functions for the built-in auth router.
|
|
110
|
+
*
|
|
111
|
+
* Each key matches the internal service function name. When provided, the
|
|
112
|
+
* custom function replaces the default service call for that route while the
|
|
113
|
+
* router still handles request parsing, input validation, and response formatting.
|
|
114
|
+
*
|
|
115
|
+
* The function signatures mirror the internal services exactly but without the
|
|
116
|
+
* `config` parameter — the library passes config at bind time.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* createAuth({
|
|
120
|
+
* // ...
|
|
121
|
+
* router: {
|
|
122
|
+
* login: async (input) => {
|
|
123
|
+
* // add OTP check, custom user lookup, etc.
|
|
124
|
+
* // must return AuthResult
|
|
125
|
+
* },
|
|
126
|
+
* signup: async (input) => {
|
|
127
|
+
* // send welcome email, set default profile, etc.
|
|
128
|
+
* // must return SignupResult
|
|
129
|
+
* },
|
|
130
|
+
* },
|
|
131
|
+
* });
|
|
132
|
+
*/
|
|
133
|
+
export interface RouterHandlers {
|
|
134
|
+
/**
|
|
135
|
+
* Replaces the default register service (`POST /register`).
|
|
136
|
+
*
|
|
137
|
+
* The router validates the request body (identifier, password, roles) first,
|
|
138
|
+
* then calls this function with the parsed input. Must return a `SignupResult`.
|
|
139
|
+
* If omitted, the library's built-in registration logic runs instead.
|
|
140
|
+
*
|
|
141
|
+
* @example
|
|
142
|
+
* register: async (input) => {
|
|
143
|
+
* const result = await defaultRegister(input);
|
|
144
|
+
* if (result.success) {
|
|
145
|
+
* await emailService.sendWelcome(input.identifier);
|
|
146
|
+
* }
|
|
147
|
+
* return result;
|
|
148
|
+
* }
|
|
149
|
+
*/
|
|
150
|
+
register?: (input: SignupInput) => Promise<SignupResult>;
|
|
151
|
+
/**
|
|
152
|
+
* Replaces the default login service.
|
|
153
|
+
*
|
|
154
|
+
* The router validates the request body (identifier, password) first,
|
|
155
|
+
* then calls this function with the parsed input. Must return an `AuthResult`.
|
|
156
|
+
* If omitted, the library's built-in login logic runs instead.
|
|
157
|
+
*
|
|
158
|
+
* @example
|
|
159
|
+
* login: async (input) => {
|
|
160
|
+
* // verify OTP before issuing tokens
|
|
161
|
+
* const otpValid = await redis.get(`otp:${input.identifier}`);
|
|
162
|
+
* if (!otpValid) {
|
|
163
|
+
* return { success: false, error: new AuthError('INVALID_CREDENTIALS', 'OTP required') };
|
|
164
|
+
* }
|
|
165
|
+
* return defaultLogin(input);
|
|
166
|
+
* }
|
|
167
|
+
*/
|
|
168
|
+
login?: (input: LoginInput) => Promise<AuthResult>;
|
|
169
|
+
/**
|
|
170
|
+
* Replaces the default refresh service.
|
|
171
|
+
*
|
|
172
|
+
* Receives the raw refresh token string extracted from the cookie.
|
|
173
|
+
* Must return a `RefreshResult`. If omitted, the built-in session-rotation
|
|
174
|
+
* logic runs instead.
|
|
175
|
+
*
|
|
176
|
+
* @example
|
|
177
|
+
* refresh: async (refreshToken) => {
|
|
178
|
+
* const result = await defaultRefresh(refreshToken);
|
|
179
|
+
* if (result.success) {
|
|
180
|
+
* await auditLog.record('token_rotated', result.user.id);
|
|
181
|
+
* }
|
|
182
|
+
* return result;
|
|
183
|
+
* }
|
|
184
|
+
*/
|
|
185
|
+
refresh?: (refreshToken: string) => Promise<RefreshResult>;
|
|
186
|
+
/**
|
|
187
|
+
* Replaces the default logout service.
|
|
188
|
+
*
|
|
189
|
+
* Receives the raw refresh token from the cookie, or `undefined` if no cookie
|
|
190
|
+
* was present. The router clears the cookie after this function resolves.
|
|
191
|
+
* If omitted, the built-in session deletion logic runs instead.
|
|
192
|
+
*
|
|
193
|
+
* @example
|
|
194
|
+
* logout: async (refreshToken) => {
|
|
195
|
+
* if (refreshToken) {
|
|
196
|
+
* await defaultLogout(refreshToken);
|
|
197
|
+
* await auditLog.record('logout', refreshToken);
|
|
198
|
+
* }
|
|
199
|
+
* }
|
|
200
|
+
*/
|
|
201
|
+
logout?: (refreshToken: string | undefined) => Promise<void>;
|
|
202
|
+
/**
|
|
203
|
+
* Replaces the default logoutAll service.
|
|
204
|
+
*
|
|
205
|
+
* Receives the authenticated user's ID (from `req.user`, set by `protect()`).
|
|
206
|
+
* If omitted, the built-in "delete all sessions" logic runs instead.
|
|
207
|
+
*
|
|
208
|
+
* @example
|
|
209
|
+
* logoutAll: async (userId) => {
|
|
210
|
+
* await defaultLogoutAll(userId);
|
|
211
|
+
* await notifyService.push(userId, 'You have been signed out from all devices.');
|
|
212
|
+
* }
|
|
213
|
+
*/
|
|
214
|
+
logoutAll?: (userId: string) => Promise<void>;
|
|
215
|
+
/**
|
|
216
|
+
* Replaces the default assignRoles service.
|
|
217
|
+
*
|
|
218
|
+
* The router validates the request body and params first, then calls this
|
|
219
|
+
* function with the target `userId` and the validated `roles` array.
|
|
220
|
+
* Must return an `AssignRolesResult`. If omitted, the built-in role-merge
|
|
221
|
+
* logic runs instead.
|
|
222
|
+
*
|
|
223
|
+
* @example
|
|
224
|
+
* assignRoles: async (userId, roles) => {
|
|
225
|
+
* const result = await defaultAssignRoles(userId, roles);
|
|
226
|
+
* if (result.success) {
|
|
227
|
+
* await auditLog.record('roles_assigned', { userId, roles });
|
|
228
|
+
* }
|
|
229
|
+
* return result;
|
|
230
|
+
* }
|
|
231
|
+
*/
|
|
232
|
+
assignRoles?: (userId: string, roles: string[]) => Promise<AssignRolesResult>;
|
|
233
|
+
}
|
|
100
234
|
/**
|
|
101
235
|
* Configuration passed to {@link createAuth}.
|
|
102
236
|
*
|
|
@@ -146,11 +280,57 @@ export interface AuthConfig<TRole extends string = string> {
|
|
|
146
280
|
validRoles: readonly TRole[];
|
|
147
281
|
/** ORM adapter that connects the library to your database. */
|
|
148
282
|
adapter: AuthAdapter;
|
|
283
|
+
/**
|
|
284
|
+
* API key required to call `POST /register`.
|
|
285
|
+
*
|
|
286
|
+
* When set, the `/register` endpoint expects an `X-Api-Key` header whose
|
|
287
|
+
* value matches this string exactly. Requests without the header, or with
|
|
288
|
+
* the wrong value, are rejected with HTTP 401 (`UNAUTHORIZED`).
|
|
289
|
+
*
|
|
290
|
+
* Use this to restrict self-registration — for example, only your own
|
|
291
|
+
* back-office service or admin panel should be able to create new accounts,
|
|
292
|
+
* so you never expose user registration to arbitrary callers.
|
|
293
|
+
*
|
|
294
|
+
* @example
|
|
295
|
+
* createAuth({
|
|
296
|
+
* // ...
|
|
297
|
+
* apiKey: process.env.REGISTER_API_KEY!,
|
|
298
|
+
* });
|
|
299
|
+
*
|
|
300
|
+
* // Client must send:
|
|
301
|
+
* // POST /auth/register
|
|
302
|
+
* // X-Api-Key: <value of REGISTER_API_KEY>
|
|
303
|
+
*/
|
|
304
|
+
apiKey?: string;
|
|
305
|
+
/**
|
|
306
|
+
* Custom service functions for individual routes in the built-in auth router.
|
|
307
|
+
*
|
|
308
|
+
* The router still handles request parsing, validation, and response formatting.
|
|
309
|
+
* Only the core service logic is replaced by your function.
|
|
310
|
+
*
|
|
311
|
+
* @example
|
|
312
|
+
* createAuth({
|
|
313
|
+
* // ...
|
|
314
|
+
* router: {
|
|
315
|
+
* login: async (input) => {
|
|
316
|
+
* // verify OTP, then delegate to default or return custom result
|
|
317
|
+
* return { success: true, accessToken, refreshToken, user };
|
|
318
|
+
* },
|
|
319
|
+
* register: async (input) => {
|
|
320
|
+
* // send welcome email after successful registration
|
|
321
|
+
* const result = await defaultRegister(input);
|
|
322
|
+
* if (result.success) await emailService.sendWelcome(input.identifier);
|
|
323
|
+
* return result;
|
|
324
|
+
* },
|
|
325
|
+
* },
|
|
326
|
+
* });
|
|
327
|
+
*/
|
|
328
|
+
router?: RouterHandlers;
|
|
149
329
|
/**
|
|
150
330
|
* When set, the built-in router (`auth.router()`) stores the refresh token
|
|
151
331
|
* in an httpOnly cookie instead of returning it in the response body.
|
|
152
332
|
*
|
|
153
|
-
* The `refreshToken` field is omitted from `/login`, `/
|
|
333
|
+
* The `refreshToken` field is omitted from `/login`, `/register`, and `/refresh`
|
|
154
334
|
* responses. The `/logout` and `/logout-all` routes automatically clear the cookie.
|
|
155
335
|
*
|
|
156
336
|
* No extra middleware (e.g. `cookie-parser`) is required.
|
|
@@ -195,12 +375,18 @@ export interface CookieConfig {
|
|
|
195
375
|
*/
|
|
196
376
|
path?: string;
|
|
197
377
|
}
|
|
198
|
-
/**
|
|
378
|
+
/**
|
|
379
|
+
* The user payload injected as `req.user` after `protect()` runs.
|
|
380
|
+
*
|
|
381
|
+
* Access tokens issued by sentri >= 1.1.0 embed a `sessionId` that is
|
|
382
|
+
* validated against the database on every request. Tokens from older
|
|
383
|
+
* versions that lack this claim are accepted but bypass session validation.
|
|
384
|
+
*/
|
|
199
385
|
export interface AuthUser<TRole extends string = string> {
|
|
200
386
|
id: string;
|
|
201
387
|
/**
|
|
202
388
|
* The credential identifier for this user (email, username, phone, etc.).
|
|
203
|
-
* Reflects whatever value was passed as `identifier` at
|
|
389
|
+
* Reflects whatever value was passed as `identifier` at registration or login.
|
|
204
390
|
*/
|
|
205
391
|
identifier: string;
|
|
206
392
|
roles: TRole[];
|