sentri 1.0.4 → 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.
Files changed (53) hide show
  1. package/README.md +314 -860
  2. package/dist/cli.js +79 -26
  3. package/dist/cli.js.map +1 -1
  4. package/dist/client.d.ts +34 -69
  5. package/dist/client.d.ts.map +1 -1
  6. package/dist/client.js +0 -6
  7. package/dist/client.js.map +1 -1
  8. package/dist/index.d.ts +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js.map +1 -1
  11. package/dist/libs/config.d.ts +45 -1
  12. package/dist/libs/config.d.ts.map +1 -1
  13. package/dist/libs/config.js +40 -2
  14. package/dist/libs/config.js.map +1 -1
  15. package/dist/libs/hash.d.ts +14 -0
  16. package/dist/libs/hash.d.ts.map +1 -1
  17. package/dist/libs/hash.js +14 -0
  18. package/dist/libs/hash.js.map +1 -1
  19. package/dist/libs/token.d.ts +37 -0
  20. package/dist/libs/token.d.ts.map +1 -1
  21. package/dist/libs/token.js +63 -0
  22. package/dist/libs/token.js.map +1 -1
  23. package/dist/middleware/authorize.d.ts +15 -0
  24. package/dist/middleware/authorize.d.ts.map +1 -1
  25. package/dist/middleware/authorize.js +18 -3
  26. package/dist/middleware/authorize.js.map +1 -1
  27. package/dist/middleware/permit.d.ts +8 -8
  28. package/dist/middleware/permit.d.ts.map +1 -1
  29. package/dist/middleware/permit.js +10 -10
  30. package/dist/middleware/permit.js.map +1 -1
  31. package/dist/middleware/protect.d.ts +17 -0
  32. package/dist/middleware/protect.d.ts.map +1 -1
  33. package/dist/middleware/protect.js +22 -5
  34. package/dist/middleware/protect.js.map +1 -1
  35. package/dist/middleware/router.d.ts +10 -6
  36. package/dist/middleware/router.d.ts.map +1 -1
  37. package/dist/middleware/router.js +122 -124
  38. package/dist/middleware/router.js.map +1 -1
  39. package/dist/services/auth.d.ts +78 -2
  40. package/dist/services/auth.d.ts.map +1 -1
  41. package/dist/services/auth.js +90 -5
  42. package/dist/services/auth.js.map +1 -1
  43. package/dist/types/auth.d.ts +176 -2
  44. package/dist/types/auth.d.ts.map +1 -1
  45. package/dist/types/auth.js +20 -1
  46. package/dist/types/auth.js.map +1 -1
  47. package/package.json +11 -3
  48. package/templates/drizzle/adapter.ts +154 -0
  49. package/templates/drizzle/auth.ts +47 -0
  50. package/templates/drizzle/schema.ts +47 -0
  51. package/templates/prisma/adapter.ts +122 -0
  52. package/templates/prisma/auth.ts +50 -0
  53. /package/templates/{schema.prisma → prisma/schema.prisma} +0 -0
@@ -1,12 +1,28 @@
1
1
  import jwt, {} from 'jsonwebtoken';
2
2
  import { AuthError } from '../errors/AuthError.js';
3
3
  import { resolveConfig } from './config.js';
4
+ /**
5
+ * Derive separate HMAC secrets for access and refresh tokens from a single
6
+ * root secret by appending a domain suffix.
7
+ *
8
+ * Using distinct secrets prevents a refresh token from being accepted as an
9
+ * access token and vice versa.
10
+ */
4
11
  function deriveSecrets(secret) {
5
12
  return {
6
13
  access: `${secret}:access`,
7
14
  refresh: `${secret}:refresh`,
8
15
  };
9
16
  }
17
+ /**
18
+ * Sign a JWT payload with the given secret and options.
19
+ *
20
+ * @param payload - Claims to embed in the token.
21
+ * @param secret - HMAC signing key.
22
+ * @param expiresIn - Expiry duration string (e.g. `'15m'`) or seconds.
23
+ * @param algorithm - HMAC algorithm variant.
24
+ * @returns Compact JWT string.
25
+ */
10
26
  function sign(payload, secret, expiresIn, algorithm) {
11
27
  const options = {
12
28
  expiresIn: expiresIn,
@@ -14,6 +30,16 @@ function sign(payload, secret, expiresIn, algorithm) {
14
30
  };
15
31
  return jwt.sign(payload, secret, options);
16
32
  }
33
+ /**
34
+ * Verify and decode a JWT, mapping jsonwebtoken errors to typed {@link AuthError}s.
35
+ *
36
+ * @param token - Compact JWT string to verify.
37
+ * @param secret - HMAC key used to sign the token.
38
+ * @param algorithm - Expected signing algorithm.
39
+ * @returns Decoded payload cast to `T`.
40
+ * @throws {AuthError} With `TOKEN_EXPIRED` if the token's `exp` claim is in the past.
41
+ * @throws {AuthError} With `TOKEN_INVALID` for any other verification failure.
42
+ */
17
43
  function verify(token, secret, algorithm) {
18
44
  try {
19
45
  const decoded = jwt.verify(token, secret, { algorithms: [algorithm] });
@@ -31,21 +57,58 @@ function verify(token, secret, algorithm) {
31
57
  throw new AuthError('TOKEN_INVALID', 'Token is invalid or malformed');
32
58
  }
33
59
  }
60
+ /**
61
+ * Sign a short-lived access token containing the user's identity and roles.
62
+ *
63
+ * Uses the access-specific secret derived from config and the configured
64
+ * `accessExpiresIn` duration and HMAC algorithm.
65
+ *
66
+ * @param payload - The {@link AuthUser} payload to embed (id, identifier, roles).
67
+ * @param config - Auth configuration used to derive the secret and options.
68
+ * @returns Compact JWT string.
69
+ */
34
70
  export function signAccessToken(payload, config) {
35
71
  const resolved = resolveConfig(config);
36
72
  const { access } = deriveSecrets(resolved.secret);
37
73
  return sign(payload, access, resolved.accessExpiresIn, resolved.algorithm);
38
74
  }
75
+ /**
76
+ * Sign a long-lived refresh token bound to a specific session ID.
77
+ *
78
+ * Uses the refresh-specific secret derived from config and the configured
79
+ * `refreshExpiresIn` duration. The session ID is embedded as the sole claim
80
+ * so the token can be used to look up and rotate the session.
81
+ *
82
+ * @param sessionId - The database session ID to bind to this token.
83
+ * @param config - Auth configuration used to derive the secret and options.
84
+ * @returns Compact JWT string.
85
+ */
39
86
  export function signRefreshToken(sessionId, config) {
40
87
  const resolved = resolveConfig(config);
41
88
  const { refresh } = deriveSecrets(resolved.secret);
42
89
  return sign({ sessionId }, refresh, resolved.refreshExpiresIn, resolved.algorithm);
43
90
  }
91
+ /**
92
+ * Verify an access token and return its decoded {@link AuthUser} payload.
93
+ *
94
+ * @param token - Compact JWT access token string.
95
+ * @param config - Auth configuration used to derive the secret and algorithm.
96
+ * @returns Decoded `AuthUser` payload (id, identifier, roles).
97
+ * @throws {AuthError} With `TOKEN_EXPIRED` if expired, `TOKEN_INVALID` otherwise.
98
+ */
44
99
  export function verifyAccessToken(token, config) {
45
100
  const resolved = resolveConfig(config);
46
101
  const { access } = deriveSecrets(resolved.secret);
47
102
  return verify(token, access, resolved.algorithm);
48
103
  }
104
+ /**
105
+ * Verify a refresh token and return the embedded session ID.
106
+ *
107
+ * @param token - Compact JWT refresh token string.
108
+ * @param config - Auth configuration used to derive the secret and algorithm.
109
+ * @returns Object with `sessionId` matching the one passed to {@link signRefreshToken}.
110
+ * @throws {AuthError} With `TOKEN_EXPIRED` if expired, `TOKEN_INVALID` otherwise.
111
+ */
49
112
  export function verifyRefreshToken(token, config) {
50
113
  const resolved = resolveConfig(config);
51
114
  const { refresh } = deriveSecrets(resolved.secret);
@@ -1 +1 @@
1
- {"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/libs/token.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../../src/libs/token.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,18 @@
1
1
  import type { RequestHandler } from 'express';
2
+ /**
3
+ * Express middleware factory for role-based access control (RBAC).
4
+ *
5
+ * Passes if the authenticated user (set by `protect()`) has **at least one**
6
+ * of the specified `allowedRoles`. Calls `next(AuthError)` with code `FORBIDDEN`
7
+ * if no roles match, or `UNAUTHORIZED` if `req.user` is absent.
8
+ *
9
+ * Must be used **after** `protect()`.
10
+ *
11
+ * @param allowedRoles - One or more role strings. The user needs at least one of them.
12
+ * @returns An Express `RequestHandler` that enforces the role check.
13
+ *
14
+ * @example
15
+ * router.delete('/posts/:id', protect(config), authorize('admin', 'moderator'), handler);
16
+ */
2
17
  export declare function authorize<TRole extends string>(...allowedRoles: TRole[]): RequestHandler;
3
18
  //# sourceMappingURL=authorize.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../../src/middleware/authorize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG9C,wBAAgB,SAAS,CAAC,KAAK,SAAS,MAAM,EAAE,GAAG,YAAY,EAAE,KAAK,EAAE,GAAG,cAAc,CAcxF"}
1
+ {"version":3,"file":"authorize.d.ts","sourceRoot":"","sources":["../../src/middleware/authorize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG9C;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CAAC,KAAK,SAAS,MAAM,EAAE,GAAG,YAAY,EAAE,KAAK,EAAE,GAAG,cAAc,CAcxF"}
@@ -1,10 +1,25 @@
1
1
  import { AuthError } from '../errors/AuthError.js';
2
+ /**
3
+ * Express middleware factory for role-based access control (RBAC).
4
+ *
5
+ * Passes if the authenticated user (set by `protect()`) has **at least one**
6
+ * of the specified `allowedRoles`. Calls `next(AuthError)` with code `FORBIDDEN`
7
+ * if no roles match, or `UNAUTHORIZED` if `req.user` is absent.
8
+ *
9
+ * Must be used **after** `protect()`.
10
+ *
11
+ * @param allowedRoles - One or more role strings. The user needs at least one of them.
12
+ * @returns An Express `RequestHandler` that enforces the role check.
13
+ *
14
+ * @example
15
+ * router.delete('/posts/:id', protect(config), authorize('admin', 'moderator'), handler);
16
+ */
2
17
  export function authorize(...allowedRoles) {
3
- return (req, _res, next) => {
4
- if (!req.user) {
18
+ return (request, _response, next) => {
19
+ if (!request.user) {
5
20
  return next(new AuthError('UNAUTHORIZED', 'Not authenticated'));
6
21
  }
7
- const userRoles = req.user.roles;
22
+ const userRoles = request.user.roles;
8
23
  const hasRole = allowedRoles.some((role) => userRoles.includes(role));
9
24
  if (!hasRole) {
10
25
  return next(new AuthError('FORBIDDEN', `Requires one of roles: ${allowedRoles.join(', ')}`));
@@ -1 +1 @@
1
- {"version":3,"file":"authorize.js","sourceRoot":"","sources":["../../src/middleware/authorize.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD,MAAM,UAAU,SAAS,CAAuB,GAAG,YAAqB;IACtE,OAAO,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;QACzB,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACd,OAAO,IAAI,CAAC,IAAI,SAAS,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC,CAAC;QAClE,CAAC;QACD,MAAM,SAAS,GAAsB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC;QACpD,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QACtE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CACT,IAAI,SAAS,CAAC,WAAW,EAAE,0BAA0B,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAChF,CAAC;QACJ,CAAC;QACD,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"authorize.js","sourceRoot":"","sources":["../../src/middleware/authorize.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAEnD;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,SAAS,CAAuB,GAAG,YAAqB;IACtE,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE;QAClC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,OAAO,IAAI,CAAC,IAAI,SAAS,CAAC,cAAc,EAAE,mBAAmB,CAAC,CAAC,CAAC;QAClE,CAAC;QACD,MAAM,SAAS,GAAsB,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;QACxD,MAAM,OAAO,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QACtE,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO,IAAI,CACT,IAAI,SAAS,CAAC,WAAW,EAAE,0BAA0B,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAChF,CAAC;QACJ,CAAC;QACD,IAAI,EAAE,CAAC;IACT,CAAC,CAAC;AACJ,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import type { Request, RequestHandler } from 'express';
2
2
  /** A function that determines whether the current request is permitted. */
3
- export type PermitCheck = (req: Request) => boolean | Promise<boolean>;
3
+ export type PermitCheck = (request: Request) => boolean | Promise<boolean>;
4
4
  /**
5
5
  * Options for {@link permit} when you need role-bypass alongside a resource check.
6
6
  *
@@ -8,9 +8,9 @@ export type PermitCheck = (req: Request) => boolean | Promise<boolean>;
8
8
  * // Admins can edit any post; others only their own
9
9
  * auth.permit({
10
10
  * roles: ['admin'],
11
- * check: async (req) => {
12
- * const post = await db.findPost(req.params['id']);
13
- * return post?.authorId === req.user!.id;
11
+ * check: async (request) => {
12
+ * const post = await db.findPost(request.params['id']);
13
+ * return post?.authorId === request.user!.id;
14
14
  * },
15
15
  * })
16
16
  */
@@ -40,7 +40,7 @@ export interface PermitOptions<TRole extends string> {
40
40
  * // Simple ownership check
41
41
  * router.put('/users/:id',
42
42
  * auth.protect(),
43
- * auth.permit((req) => req.user!.id === req.params['id']),
43
+ * auth.permit((request) => request.user!.id === request.params['id']),
44
44
  * updateUserHandler,
45
45
  * );
46
46
  *
@@ -50,9 +50,9 @@ export interface PermitOptions<TRole extends string> {
50
50
  * auth.protect(),
51
51
  * auth.permit({
52
52
  * roles: ['admin'],
53
- * check: async (req) => {
54
- * const post = await db.post.findUnique({ where: { id: req.params['id'] } });
55
- * return post?.authorId === req.user!.id;
53
+ * check: async (request) => {
54
+ * const post = await db.post.findUnique({ where: { id: request.params['id'] } });
55
+ * return post?.authorId === request.user!.id;
56
56
  * },
57
57
  * }),
58
58
  * deletePostHandler,
@@ -1 +1 @@
1
- {"version":3,"file":"permit.d.ts","sourceRoot":"","sources":["../../src/middleware/permit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAGvD,2EAA2E;AAC3E,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEvE;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,SAAS,MAAM;IACjD;;;OAGG;IACH,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC;IAChB;;;;OAIG;IACH,KAAK,EAAE,WAAW,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,MAAM,CAAC,KAAK,SAAS,MAAM,EACzC,cAAc,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,WAAW,GACjD,cAAc,CA4BhB"}
1
+ {"version":3,"file":"permit.d.ts","sourceRoot":"","sources":["../../src/middleware/permit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAGvD,2EAA2E;AAC3E,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAE3E;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa,CAAC,KAAK,SAAS,MAAM;IACjD;;;OAGG;IACH,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC;IAChB;;;;OAIG;IACH,KAAK,EAAE,WAAW,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,MAAM,CAAC,KAAK,SAAS,MAAM,EACzC,cAAc,EAAE,aAAa,CAAC,KAAK,CAAC,GAAG,WAAW,GACjD,cAAc,CA4BhB"}
@@ -12,7 +12,7 @@ import { AuthError } from '../errors/AuthError.js';
12
12
  * // Simple ownership check
13
13
  * router.put('/users/:id',
14
14
  * auth.protect(),
15
- * auth.permit((req) => req.user!.id === req.params['id']),
15
+ * auth.permit((request) => request.user!.id === request.params['id']),
16
16
  * updateUserHandler,
17
17
  * );
18
18
  *
@@ -22,9 +22,9 @@ import { AuthError } from '../errors/AuthError.js';
22
22
  * auth.protect(),
23
23
  * auth.permit({
24
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;
25
+ * check: async (request) => {
26
+ * const post = await db.post.findUnique({ where: { id: request.params['id'] } });
27
+ * return post?.authorId === request.user!.id;
28
28
  * },
29
29
  * }),
30
30
  * deletePostHandler,
@@ -34,18 +34,18 @@ export function permit(optionsOrCheck) {
34
34
  const options = typeof optionsOrCheck === 'function'
35
35
  ? { check: optionsOrCheck }
36
36
  : optionsOrCheck;
37
- return async (req, _res, next) => {
38
- if (!req.user) {
37
+ return async (request, _response, next) => {
38
+ if (!request.user) {
39
39
  return next(new AuthError('UNAUTHORIZED', 'Not authenticated'));
40
40
  }
41
41
  if (options.roles && options.roles.length > 0) {
42
- const userRoles = req.user.roles;
42
+ const userRoles = request.user.roles;
43
43
  const hasBypassRole = options.roles.some((role) => userRoles.includes(role));
44
44
  if (hasBypassRole)
45
45
  return next();
46
46
  }
47
47
  try {
48
- const allowed = await options.check(req);
48
+ const allowed = await options.check(request);
49
49
  if (allowed) {
50
50
  next();
51
51
  }
@@ -53,8 +53,8 @@ export function permit(optionsOrCheck) {
53
53
  next(new AuthError('FORBIDDEN', 'You do not have permission to perform this action'));
54
54
  }
55
55
  }
56
- catch (err) {
57
- next(err);
56
+ catch (error) {
57
+ next(error);
58
58
  }
59
59
  };
60
60
  }
@@ -1 +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"}
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,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE;QACxC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;YAClB,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,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC;YACxD,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,OAAO,CAAC,CAAC;YAC7C,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,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,KAAK,CAAC,CAAC;QACd,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -1,4 +1,21 @@
1
1
  import type { RequestHandler } from 'express';
2
2
  import type { AuthConfig } from '../types/auth.js';
3
+ /**
4
+ * Express middleware factory that enforces JWT authentication.
5
+ *
6
+ * Reads the `Authorization: Bearer <token>` header, verifies the access token,
7
+ * and attaches the decoded payload to `req.user`. Calls `next(AuthError)` on
8
+ * any failure so your error handler can convert it to an HTTP response.
9
+ *
10
+ * Must be used **before** `authorize()` or `permit()`.
11
+ *
12
+ * @param config - Auth configuration used to verify the token.
13
+ * @returns An Express `RequestHandler` that populates `req.user` on success.
14
+ *
15
+ * @example
16
+ * router.get('/profile', protect(config), (req, res) => {
17
+ * res.json(req.user);
18
+ * });
19
+ */
3
20
  export declare function protect(config: AuthConfig): RequestHandler;
4
21
  //# sourceMappingURL=protect.d.ts.map
@@ -1 +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"}
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;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,UAAU,GAAG,cAAc,CAc1D"}
@@ -1,18 +1,35 @@
1
1
  import { AuthError } from '../errors/AuthError.js';
2
2
  import { verifyAccessToken } from '../libs/token.js';
3
+ /**
4
+ * Express middleware factory that enforces JWT authentication.
5
+ *
6
+ * Reads the `Authorization: Bearer <token>` header, verifies the access token,
7
+ * and attaches the decoded payload to `req.user`. Calls `next(AuthError)` on
8
+ * any failure so your error handler can convert it to an HTTP response.
9
+ *
10
+ * Must be used **before** `authorize()` or `permit()`.
11
+ *
12
+ * @param config - Auth configuration used to verify the token.
13
+ * @returns An Express `RequestHandler` that populates `req.user` on success.
14
+ *
15
+ * @example
16
+ * router.get('/profile', protect(config), (req, res) => {
17
+ * res.json(req.user);
18
+ * });
19
+ */
3
20
  export function protect(config) {
4
- return (req, _res, next) => {
5
- const authHeader = req.headers['authorization'];
21
+ return (request, _response, next) => {
22
+ const authHeader = request.headers['authorization'];
6
23
  if (!authHeader?.startsWith('Bearer ')) {
7
24
  return next(new AuthError('UNAUTHORIZED', 'Missing or malformed Authorization header'));
8
25
  }
9
26
  const token = authHeader.slice(7);
10
27
  try {
11
- req.user = verifyAccessToken(token, config);
28
+ request.user = verifyAccessToken(token, config);
12
29
  next();
13
30
  }
14
- catch (err) {
15
- next(err);
31
+ catch (error) {
32
+ next(error);
16
33
  }
17
34
  };
18
35
  }
@@ -1 +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"}
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;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,OAAO,CAAC,MAAkB;IACxC,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE;QAClC,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,eAAe,CAAC,CAAC;QACpD,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,OAAO,CAAC,IAAI,GAAG,iBAAiB,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAChD,IAAI,EAAE,CAAC;QACT,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,KAAK,CAAC,CAAC;QACd,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
@@ -6,12 +6,13 @@ import type { AuthConfig } from '../types/auth.js';
6
6
  * Mount it once and all routes are ready:
7
7
  *
8
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
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
+ * POST /users/:userId/roles — assign roles (admin only)
15
16
  * ```
16
17
  *
17
18
  * Requires `express.json()` to be applied before the router.
@@ -19,6 +20,9 @@ import type { AuthConfig } from '../types/auth.js';
19
20
  * When `cookie` is set in config, the refresh token is stored in an httpOnly
20
21
  * cookie automatically — no `cookie-parser` needed.
21
22
  *
23
+ * When `router` is set in config, individual service functions can be replaced
24
+ * while the router still handles validation and response formatting.
25
+ *
22
26
  * @example
23
27
  * app.use(express.json());
24
28
  * app.use('/auth', auth.router());
@@ -1 +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"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/middleware/router.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAkD,MAAM,SAAS,CAAC;AAEjF,OAAO,KAAK,EAAE,UAAU,EAA2B,MAAM,kBAAkB,CAAC;AAmE5E;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,SAAS,MAAM,EAAE,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC,GAAG,MAAM,CA8KxF"}