sentri 1.0.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 +1044 -0
- package/dist/client.d.ts +158 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +49 -0
- package/dist/client.js.map +1 -0
- package/dist/errors/AuthError.d.ts +40 -0
- package/dist/errors/AuthError.d.ts.map +1 -0
- package/dist/errors/AuthError.js +29 -0
- package/dist/errors/AuthError.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/libs/config.d.ts +18 -0
- package/dist/libs/config.d.ts.map +1 -0
- package/dist/libs/config.js +59 -0
- package/dist/libs/config.js.map +1 -0
- package/dist/libs/hash.d.ts +3 -0
- package/dist/libs/hash.d.ts.map +1 -0
- package/dist/libs/hash.js +8 -0
- package/dist/libs/hash.js.map +1 -0
- package/dist/libs/token.d.ts +8 -0
- package/dist/libs/token.d.ts.map +1 -0
- package/dist/libs/token.js +54 -0
- package/dist/libs/token.js.map +1 -0
- package/dist/middleware/authorize.d.ts +3 -0
- package/dist/middleware/authorize.d.ts.map +1 -0
- package/dist/middleware/authorize.js +15 -0
- package/dist/middleware/authorize.js.map +1 -0
- package/dist/middleware/permit.d.ts +62 -0
- package/dist/middleware/permit.d.ts.map +1 -0
- package/dist/middleware/permit.js +61 -0
- package/dist/middleware/permit.js.map +1 -0
- package/dist/middleware/protect.d.ts +4 -0
- package/dist/middleware/protect.d.ts.map +1 -0
- package/dist/middleware/protect.js +19 -0
- package/dist/middleware/protect.js.map +1 -0
- package/dist/middleware/router.d.ts +27 -0
- package/dist/middleware/router.d.ts.map +1 -0
- package/dist/middleware/router.js +244 -0
- package/dist/middleware/router.js.map +1 -0
- package/dist/services/auth.d.ts +7 -0
- package/dist/services/auth.d.ts.map +1 -0
- package/dist/services/auth.js +84 -0
- package/dist/services/auth.js.map +1 -0
- package/dist/types/auth.d.ts +234 -0
- package/dist/types/auth.d.ts.map +1 -0
- package/dist/types/auth.js +2 -0
- package/dist/types/auth.js.map +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { AuthError } from '../errors/AuthError.js';
|
|
2
|
+
/**
|
|
3
|
+
* Express middleware factory for resource-level permission checks.
|
|
4
|
+
*
|
|
5
|
+
* Must be used **after** `protect()`. Evaluates a check function against the
|
|
6
|
+
* current request; calls `next(AuthError)` with code `FORBIDDEN` if it returns `false`.
|
|
7
|
+
*
|
|
8
|
+
* Accepts either a bare check function or an options object with an optional
|
|
9
|
+
* `roles` list whose members bypass the check entirely.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* // Simple ownership check
|
|
13
|
+
* router.put('/users/:id',
|
|
14
|
+
* auth.protect(),
|
|
15
|
+
* auth.permit((req) => req.user!.id === req.params['id']),
|
|
16
|
+
* updateUserHandler,
|
|
17
|
+
* );
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* // Admins bypass the check; others must own the post
|
|
21
|
+
* router.delete('/posts/:id',
|
|
22
|
+
* auth.protect(),
|
|
23
|
+
* auth.permit({
|
|
24
|
+
* roles: ['admin'],
|
|
25
|
+
* check: async (req) => {
|
|
26
|
+
* const post = await db.post.findUnique({ where: { id: req.params['id'] } });
|
|
27
|
+
* return post?.authorId === req.user!.id;
|
|
28
|
+
* },
|
|
29
|
+
* }),
|
|
30
|
+
* deletePostHandler,
|
|
31
|
+
* );
|
|
32
|
+
*/
|
|
33
|
+
export function permit(optionsOrCheck) {
|
|
34
|
+
const options = typeof optionsOrCheck === 'function'
|
|
35
|
+
? { check: optionsOrCheck }
|
|
36
|
+
: optionsOrCheck;
|
|
37
|
+
return async (req, _res, next) => {
|
|
38
|
+
if (!req.user) {
|
|
39
|
+
return next(new AuthError('UNAUTHORIZED', 'Not authenticated'));
|
|
40
|
+
}
|
|
41
|
+
if (options.roles && options.roles.length > 0) {
|
|
42
|
+
const userRoles = req.user.roles;
|
|
43
|
+
const hasBypassRole = options.roles.some((role) => userRoles.includes(role));
|
|
44
|
+
if (hasBypassRole)
|
|
45
|
+
return next();
|
|
46
|
+
}
|
|
47
|
+
try {
|
|
48
|
+
const allowed = await options.check(req);
|
|
49
|
+
if (allowed) {
|
|
50
|
+
next();
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
next(new AuthError('FORBIDDEN', 'You do not have permission to perform this action'));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
next(err);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=permit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"permit.js","sourceRoot":"","sources":["../../src/middleware/permit.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAgCnD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,MAAM,CACpB,cAAkD;IAElD,MAAM,OAAO,GACX,OAAO,cAAc,KAAK,UAAU;QAClC,CAAC,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE;QAC3B,CAAC,CAAC,cAAc,CAAC;IAErB,OAAO,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QAC/B,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACd,OAAO,IAAI,CAAC,IAAI,SAAS,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC,CAAC;QAClE,CAAC;QAED,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,MAAM,SAAS,GAAsB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;YACpD,MAAM,aAAa,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;YAC7E,IAAI,aAAa;gBAAE,OAAO,IAAI,EAAE,CAAC;QACnC,CAAC;QAED,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YACzC,IAAI,OAAO,EAAE,CAAC;gBACZ,IAAI,EAAE,CAAC;YACT,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,IAAI,SAAS,CAAC,WAAW,EAAE,mDAAmD,CAAC,CAAC,CAAC;YACxF,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protect.d.ts","sourceRoot":"","sources":["../../src/middleware/protect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG9C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,cAAc,CAc1D"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AuthError } from '../errors/AuthError.js';
|
|
2
|
+
import { verifyAccessToken } from '../libs/token.js';
|
|
3
|
+
export function protect(config) {
|
|
4
|
+
return (req, _res, next) => {
|
|
5
|
+
const authHeader = req.headers['authorization'];
|
|
6
|
+
if (!authHeader?.startsWith('Bearer ')) {
|
|
7
|
+
return next(new AuthError('UNAUTHORIZED', 'Missing or malformed Authorization header'));
|
|
8
|
+
}
|
|
9
|
+
const token = authHeader.slice(7);
|
|
10
|
+
try {
|
|
11
|
+
req.user = verifyAccessToken(token, config);
|
|
12
|
+
next();
|
|
13
|
+
}
|
|
14
|
+
catch (err) {
|
|
15
|
+
next(err);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=protect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protect.js","sourceRoot":"","sources":["../../src/middleware/protect.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAGrD,MAAM,UAAU,OAAO,CAAC,MAAkB;IACxC,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QACzB,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QAChD,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YACvC,OAAO,IAAI,CAAC,IAAI,SAAS,CAAC,cAAc,EAAE,2CAA2C,CAAC,CAAC,CAAC;QAC1F,CAAC;QACD,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QAClC,IAAI,CAAC;YACH,GAAG,CAAC,IAAI,GAAG,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAC5C,IAAI,EAAE,CAAC;QACT,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,GAAG,CAAC,CAAC;QACZ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import type { AuthConfig } from '../types/auth.js';
|
|
3
|
+
/**
|
|
4
|
+
* Creates a pre-built Express Router with all standard auth endpoints.
|
|
5
|
+
*
|
|
6
|
+
* Mount it once and all routes are ready:
|
|
7
|
+
*
|
|
8
|
+
* ```
|
|
9
|
+
* POST /signup — register a new user
|
|
10
|
+
* POST /login — authenticate and get tokens
|
|
11
|
+
* POST /refresh — rotate refresh token
|
|
12
|
+
* POST /logout — invalidate current session
|
|
13
|
+
* POST /logout-all — invalidate all sessions for the authenticated user
|
|
14
|
+
* GET /me — return the currently authenticated user
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Requires `express.json()` to be applied before the router.
|
|
18
|
+
*
|
|
19
|
+
* When `cookie` is set in config, the refresh token is stored in an httpOnly
|
|
20
|
+
* cookie automatically — no `cookie-parser` needed.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* app.use(express.json());
|
|
24
|
+
* app.use('/auth', auth.router());
|
|
25
|
+
*/
|
|
26
|
+
export declare function createAuthRouter<TRole extends string>(config: AuthConfig<TRole>): Router;
|
|
27
|
+
//# sourceMappingURL=router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/middleware/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAiB,MAAM,SAAS,CAAC;AAEhD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAmDnD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,SAAS,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,GAAG,MAAM,CA2LxF"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { Router } from 'express';
|
|
2
|
+
import { AuthError } from '../errors/AuthError.js';
|
|
3
|
+
import { signup, login, refresh, logout, logoutAll } from '../services/auth.js';
|
|
4
|
+
import { resolveConfig, parseExpiry } from '../libs/config.js';
|
|
5
|
+
import { protect } from './protect.js';
|
|
6
|
+
const MIN_PASSWORD_LENGTH = 8;
|
|
7
|
+
// bcrypt silently truncates input beyond 72 bytes. Enforcing a cap makes the
|
|
8
|
+
// truncation boundary explicit so two passwords that share the same first 72
|
|
9
|
+
// bytes cannot be treated as identical.
|
|
10
|
+
const MAX_PASSWORD_LENGTH = 72;
|
|
11
|
+
const MAX_IDENTIFIER_LENGTH = 255;
|
|
12
|
+
function badRequest(message) {
|
|
13
|
+
return new AuthError('VALIDATION_ERROR', message);
|
|
14
|
+
}
|
|
15
|
+
function parseBody(body) {
|
|
16
|
+
if (body === null || body === undefined || typeof body !== 'object' || Array.isArray(body)) {
|
|
17
|
+
throw new AuthError('VALIDATION_ERROR', 'Request body is missing or not a JSON object. Did you apply express.json()?');
|
|
18
|
+
}
|
|
19
|
+
return body;
|
|
20
|
+
}
|
|
21
|
+
// Read a single cookie from the raw Cookie header — no cookie-parser needed.
|
|
22
|
+
function readCookie(cookieHeader, name) {
|
|
23
|
+
if (!cookieHeader)
|
|
24
|
+
return undefined;
|
|
25
|
+
const pair = cookieHeader
|
|
26
|
+
.split(';')
|
|
27
|
+
.map((s) => s.trim())
|
|
28
|
+
.find((s) => s.startsWith(`${name}=`));
|
|
29
|
+
return pair !== undefined ? pair.slice(name.length + 1) : undefined;
|
|
30
|
+
}
|
|
31
|
+
function setCookie(res, token, config) {
|
|
32
|
+
const cfg = config.cookie;
|
|
33
|
+
const resolved = resolveConfig(config);
|
|
34
|
+
const maxAge = parseExpiry(resolved.refreshExpiresIn);
|
|
35
|
+
res.cookie(cfg.name ?? 'refresh_token', token, {
|
|
36
|
+
httpOnly: cfg.httpOnly ?? true,
|
|
37
|
+
secure: cfg.secure ?? false,
|
|
38
|
+
sameSite: cfg.sameSite ?? 'strict',
|
|
39
|
+
path: cfg.path ?? '/',
|
|
40
|
+
maxAge,
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
function clearCookie(res, config) {
|
|
44
|
+
const cfg = config.cookie;
|
|
45
|
+
res.clearCookie(cfg.name ?? 'refresh_token', { path: cfg.path ?? '/' });
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Creates a pre-built Express Router with all standard auth endpoints.
|
|
49
|
+
*
|
|
50
|
+
* Mount it once and all routes are ready:
|
|
51
|
+
*
|
|
52
|
+
* ```
|
|
53
|
+
* POST /signup — register a new user
|
|
54
|
+
* POST /login — authenticate and get tokens
|
|
55
|
+
* POST /refresh — rotate refresh token
|
|
56
|
+
* POST /logout — invalidate current session
|
|
57
|
+
* POST /logout-all — invalidate all sessions for the authenticated user
|
|
58
|
+
* GET /me — return the currently authenticated user
|
|
59
|
+
* ```
|
|
60
|
+
*
|
|
61
|
+
* Requires `express.json()` to be applied before the router.
|
|
62
|
+
*
|
|
63
|
+
* When `cookie` is set in config, the refresh token is stored in an httpOnly
|
|
64
|
+
* cookie automatically — no `cookie-parser` needed.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* app.use(express.json());
|
|
68
|
+
* app.use('/auth', auth.router());
|
|
69
|
+
*/
|
|
70
|
+
export function createAuthRouter(config) {
|
|
71
|
+
const router = Router();
|
|
72
|
+
const cookieMode = config.cookie !== undefined;
|
|
73
|
+
router.post('/signup', async (req, res, next) => {
|
|
74
|
+
try {
|
|
75
|
+
const body = parseBody(req.body);
|
|
76
|
+
const { identifier, password, roles } = body;
|
|
77
|
+
if (typeof identifier !== 'string' || identifier.trim().length === 0) {
|
|
78
|
+
throw badRequest('identifier is required and must be a non-empty string');
|
|
79
|
+
}
|
|
80
|
+
if (identifier.length > MAX_IDENTIFIER_LENGTH) {
|
|
81
|
+
throw badRequest(`identifier must not exceed ${MAX_IDENTIFIER_LENGTH} characters`);
|
|
82
|
+
}
|
|
83
|
+
if (typeof password !== 'string' || password.length < MIN_PASSWORD_LENGTH) {
|
|
84
|
+
throw badRequest(`password is required and must be at least ${MIN_PASSWORD_LENGTH} characters`);
|
|
85
|
+
}
|
|
86
|
+
if (password.length > MAX_PASSWORD_LENGTH) {
|
|
87
|
+
throw badRequest(`password must not exceed ${MAX_PASSWORD_LENGTH} characters`);
|
|
88
|
+
}
|
|
89
|
+
if (roles !== undefined && !Array.isArray(roles)) {
|
|
90
|
+
throw badRequest('roles must be an array of strings when provided');
|
|
91
|
+
}
|
|
92
|
+
if (Array.isArray(roles) && !roles.every((r) => typeof r === 'string')) {
|
|
93
|
+
throw badRequest('each role must be a string');
|
|
94
|
+
}
|
|
95
|
+
const rolesInput = Array.isArray(roles) ? roles : undefined;
|
|
96
|
+
const input = rolesInput !== undefined
|
|
97
|
+
? { identifier: identifier.trim(), password, roles: rolesInput }
|
|
98
|
+
: { identifier: identifier.trim(), password };
|
|
99
|
+
const result = await signup(input, config);
|
|
100
|
+
if (!result.success) {
|
|
101
|
+
const status = result.error.code === 'USER_ALREADY_EXISTS' ? 409 : 400;
|
|
102
|
+
res.status(status).json({ code: result.error.code, message: result.error.message });
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
if (cookieMode) {
|
|
106
|
+
setCookie(res, result.refreshToken, config);
|
|
107
|
+
res.status(201).json({ accessToken: result.accessToken, user: result.user });
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
res.status(201).json({
|
|
111
|
+
accessToken: result.accessToken,
|
|
112
|
+
refreshToken: result.refreshToken,
|
|
113
|
+
user: result.user,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
next(err);
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
router.post('/login', async (req, res, next) => {
|
|
122
|
+
try {
|
|
123
|
+
const body = parseBody(req.body);
|
|
124
|
+
const { identifier, password } = body;
|
|
125
|
+
if (typeof identifier !== 'string' || identifier.trim().length === 0) {
|
|
126
|
+
throw badRequest('identifier is required and must be a non-empty string');
|
|
127
|
+
}
|
|
128
|
+
if (identifier.length > MAX_IDENTIFIER_LENGTH) {
|
|
129
|
+
throw badRequest(`identifier must not exceed ${MAX_IDENTIFIER_LENGTH} characters`);
|
|
130
|
+
}
|
|
131
|
+
if (typeof password !== 'string' || password.length === 0) {
|
|
132
|
+
throw badRequest('password is required');
|
|
133
|
+
}
|
|
134
|
+
if (password.length > MAX_PASSWORD_LENGTH) {
|
|
135
|
+
throw badRequest(`password must not exceed ${MAX_PASSWORD_LENGTH} characters`);
|
|
136
|
+
}
|
|
137
|
+
const result = await login({ identifier: identifier.trim(), password }, config);
|
|
138
|
+
if (!result.success) {
|
|
139
|
+
res.status(401).json({ code: result.error.code, message: result.error.message });
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
if (cookieMode) {
|
|
143
|
+
setCookie(res, result.refreshToken, config);
|
|
144
|
+
res.json({ accessToken: result.accessToken, user: result.user });
|
|
145
|
+
}
|
|
146
|
+
else {
|
|
147
|
+
res.json({
|
|
148
|
+
accessToken: result.accessToken,
|
|
149
|
+
refreshToken: result.refreshToken,
|
|
150
|
+
user: result.user,
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
catch (err) {
|
|
155
|
+
next(err);
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
router.post('/refresh', async (req, res, next) => {
|
|
159
|
+
try {
|
|
160
|
+
let refreshToken;
|
|
161
|
+
if (cookieMode) {
|
|
162
|
+
const fromCookie = readCookie(req.headers['cookie'], config.cookie?.name ?? 'refresh_token');
|
|
163
|
+
if (!fromCookie) {
|
|
164
|
+
throw new AuthError('UNAUTHORIZED', 'Refresh token cookie is missing');
|
|
165
|
+
}
|
|
166
|
+
refreshToken = fromCookie;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
const body = parseBody(req.body);
|
|
170
|
+
const { refreshToken: fromBody } = body;
|
|
171
|
+
if (typeof fromBody !== 'string' || fromBody.trim().length === 0) {
|
|
172
|
+
throw badRequest('refreshToken is required');
|
|
173
|
+
}
|
|
174
|
+
refreshToken = fromBody;
|
|
175
|
+
}
|
|
176
|
+
const result = await refresh(refreshToken, config);
|
|
177
|
+
if (!result.success) {
|
|
178
|
+
if (cookieMode)
|
|
179
|
+
clearCookie(res, config);
|
|
180
|
+
res.status(401).json({ code: result.error.code, message: result.error.message });
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (cookieMode) {
|
|
184
|
+
setCookie(res, result.refreshToken, config);
|
|
185
|
+
res.json({ accessToken: result.accessToken });
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
res.json({
|
|
189
|
+
accessToken: result.accessToken,
|
|
190
|
+
refreshToken: result.refreshToken,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
catch (err) {
|
|
195
|
+
next(err);
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
router.post('/logout', async (req, res, next) => {
|
|
199
|
+
try {
|
|
200
|
+
let refreshToken;
|
|
201
|
+
if (cookieMode) {
|
|
202
|
+
const fromCookie = readCookie(req.headers['cookie'], config.cookie?.name ?? 'refresh_token');
|
|
203
|
+
if (!fromCookie) {
|
|
204
|
+
// Nothing to revoke, just clear the cookie and return success
|
|
205
|
+
clearCookie(res, config);
|
|
206
|
+
res.json({ message: 'logged out' });
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
refreshToken = fromCookie;
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
const body = parseBody(req.body);
|
|
213
|
+
const { refreshToken: fromBody } = body;
|
|
214
|
+
if (typeof fromBody !== 'string' || fromBody.trim().length === 0) {
|
|
215
|
+
throw badRequest('refreshToken is required');
|
|
216
|
+
}
|
|
217
|
+
refreshToken = fromBody;
|
|
218
|
+
}
|
|
219
|
+
await logout(refreshToken, config);
|
|
220
|
+
if (cookieMode)
|
|
221
|
+
clearCookie(res, config);
|
|
222
|
+
res.json({ message: 'logged out' });
|
|
223
|
+
}
|
|
224
|
+
catch (err) {
|
|
225
|
+
next(err);
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
router.post('/logout-all', protect(config), async (req, res, next) => {
|
|
229
|
+
try {
|
|
230
|
+
await logoutAll(req.user.id, config);
|
|
231
|
+
if (cookieMode)
|
|
232
|
+
clearCookie(res, config);
|
|
233
|
+
res.json({ message: 'all sessions revoked' });
|
|
234
|
+
}
|
|
235
|
+
catch (err) {
|
|
236
|
+
next(err);
|
|
237
|
+
}
|
|
238
|
+
});
|
|
239
|
+
router.get('/me', protect(config), (req, res) => {
|
|
240
|
+
res.json(req.user);
|
|
241
|
+
});
|
|
242
|
+
return router;
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/middleware/router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { AuthConfig, AuthResult, LoginInput, RefreshResult, SignupInput } from '../types/auth.js';
|
|
2
|
+
export declare function signup(input: SignupInput, config: AuthConfig): Promise<AuthResult>;
|
|
3
|
+
export declare function login(input: LoginInput, config: AuthConfig): Promise<AuthResult>;
|
|
4
|
+
export declare function refresh(refreshToken: string, config: AuthConfig): Promise<RefreshResult>;
|
|
5
|
+
export declare function logout(refreshToken: string, config: AuthConfig): Promise<void>;
|
|
6
|
+
export declare function logoutAll(userId: string, config: AuthConfig): Promise<void>;
|
|
7
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/services/auth.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEvG,wBAAsB,MAAM,CAC1B,KAAK,EAAE,WAAW,EAClB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,UAAU,CAAC,CAyBrB;AAED,wBAAsB,KAAK,CACzB,KAAK,EAAE,UAAU,EACjB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,UAAU,CAAC,CAoBrB;AAED,wBAAsB,OAAO,CAC3B,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,aAAa,CAAC,CA8BxB;AAED,wBAAsB,MAAM,CAC1B,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,IAAI,CAAC,CAQf;AAED,wBAAsB,SAAS,CAC7B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,UAAU,GACjB,OAAO,CAAC,IAAI,CAAC,CAEf"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { AuthError } from '../errors/AuthError.js';
|
|
2
|
+
import { hashPassword, verifyPassword } from '../libs/hash.js';
|
|
3
|
+
import { signAccessToken, signRefreshToken, verifyRefreshToken } from '../libs/token.js';
|
|
4
|
+
import { resolveConfig, parseExpiry } from '../libs/config.js';
|
|
5
|
+
export async function signup(input, config) {
|
|
6
|
+
const resolved = resolveConfig(config);
|
|
7
|
+
const requestedRoles = input.roles ?? [];
|
|
8
|
+
const invalidRoles = requestedRoles.filter((r) => !resolved.validRoles.includes(r));
|
|
9
|
+
if (invalidRoles.length > 0) {
|
|
10
|
+
return { success: false, error: new AuthError('INVALID_ROLE', `Invalid roles: ${invalidRoles.join(', ')}`) };
|
|
11
|
+
}
|
|
12
|
+
const identifier = input.identifier.trim();
|
|
13
|
+
const existing = await resolved.adapter.user.findByIdentifier(identifier);
|
|
14
|
+
if (existing) {
|
|
15
|
+
return { success: false, error: new AuthError('USER_ALREADY_EXISTS', 'User already exists') };
|
|
16
|
+
}
|
|
17
|
+
const passwordHash = await hashPassword(input.password, resolved.saltRounds);
|
|
18
|
+
const created = await resolved.adapter.user.create({ identifier, passwordHash, roles: requestedRoles });
|
|
19
|
+
const expiresAt = new Date(Date.now() + parseExpiry(resolved.refreshExpiresIn));
|
|
20
|
+
const session = await resolved.adapter.session.create({ userId: created.id, expiresAt });
|
|
21
|
+
const user = { id: created.id, identifier, roles: requestedRoles };
|
|
22
|
+
const accessToken = signAccessToken(user, config);
|
|
23
|
+
const refreshToken = signRefreshToken(session.id, config);
|
|
24
|
+
return { success: true, accessToken, refreshToken, user };
|
|
25
|
+
}
|
|
26
|
+
export async function login(input, config) {
|
|
27
|
+
const resolved = resolveConfig(config);
|
|
28
|
+
const found = await resolved.adapter.user.findByIdentifier(input.identifier.trim());
|
|
29
|
+
if (!found) {
|
|
30
|
+
return { success: false, error: new AuthError('INVALID_CREDENTIALS', 'Invalid credentials') };
|
|
31
|
+
}
|
|
32
|
+
const valid = await verifyPassword(input.password, found.passwordHash);
|
|
33
|
+
if (!valid) {
|
|
34
|
+
return { success: false, error: new AuthError('INVALID_CREDENTIALS', 'Invalid credentials') };
|
|
35
|
+
}
|
|
36
|
+
const expiresAt = new Date(Date.now() + parseExpiry(resolved.refreshExpiresIn));
|
|
37
|
+
const session = await resolved.adapter.session.create({ userId: found.id, expiresAt });
|
|
38
|
+
const user = { id: found.id, identifier: found.identifier, roles: found.roles };
|
|
39
|
+
const accessToken = signAccessToken(user, config);
|
|
40
|
+
const refreshToken = signRefreshToken(session.id, config);
|
|
41
|
+
return { success: true, accessToken, refreshToken, user };
|
|
42
|
+
}
|
|
43
|
+
export async function refresh(refreshToken, config) {
|
|
44
|
+
const resolved = resolveConfig(config);
|
|
45
|
+
let sessionId;
|
|
46
|
+
try {
|
|
47
|
+
({ sessionId } = verifyRefreshToken(refreshToken, config));
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
if (err instanceof AuthError)
|
|
51
|
+
return { success: false, error: err };
|
|
52
|
+
return { success: false, error: new AuthError('TOKEN_INVALID', 'Invalid refresh token') };
|
|
53
|
+
}
|
|
54
|
+
const session = await resolved.adapter.session.findById(sessionId);
|
|
55
|
+
if (!session) {
|
|
56
|
+
return { success: false, error: new AuthError('UNAUTHORIZED', 'Session not found or revoked') };
|
|
57
|
+
}
|
|
58
|
+
if (session.expiresAt < new Date()) {
|
|
59
|
+
await resolved.adapter.session.delete(sessionId);
|
|
60
|
+
return { success: false, error: new AuthError('TOKEN_EXPIRED', 'Session has expired') };
|
|
61
|
+
}
|
|
62
|
+
// rotate: delete old session, create new one
|
|
63
|
+
await resolved.adapter.session.delete(sessionId);
|
|
64
|
+
const expiresAt = new Date(Date.now() + parseExpiry(resolved.refreshExpiresIn));
|
|
65
|
+
const newSession = await resolved.adapter.session.create({ userId: session.userId, expiresAt });
|
|
66
|
+
const user = { id: session.user.id, identifier: session.user.identifier, roles: session.user.roles };
|
|
67
|
+
const newAccessToken = signAccessToken(user, config);
|
|
68
|
+
const newRefreshToken = signRefreshToken(newSession.id, config);
|
|
69
|
+
return { success: true, accessToken: newAccessToken, refreshToken: newRefreshToken, user };
|
|
70
|
+
}
|
|
71
|
+
export async function logout(refreshToken, config) {
|
|
72
|
+
let sessionId;
|
|
73
|
+
try {
|
|
74
|
+
({ sessionId } = verifyRefreshToken(refreshToken, config));
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return; // already invalid, nothing to revoke
|
|
78
|
+
}
|
|
79
|
+
await resolveConfig(config).adapter.session.delete(sessionId);
|
|
80
|
+
}
|
|
81
|
+
export async function logoutAll(userId, config) {
|
|
82
|
+
await resolveConfig(config).adapter.session.deleteAllForUser(userId);
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/services/auth.ts"],"names":[],"mappings":"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"}
|