expediate 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 (69) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/CONTRIBUTING.md +150 -0
  3. package/LICENSE +16 -16
  4. package/README.md +330 -444
  5. package/dist/apis.d.ts +504 -27
  6. package/dist/apis.d.ts.map +1 -1
  7. package/dist/apis.js +618 -107
  8. package/dist/apis.js.map +1 -1
  9. package/dist/cjs/index.js +4066 -0
  10. package/dist/cjs/package.json +1 -0
  11. package/dist/git.d.ts +72 -9
  12. package/dist/git.d.ts.map +1 -1
  13. package/dist/git.js +129 -74
  14. package/dist/git.js.map +1 -1
  15. package/dist/http-objects.d.ts +26 -0
  16. package/dist/http-objects.d.ts.map +1 -0
  17. package/dist/http-objects.js +588 -0
  18. package/dist/http-objects.js.map +1 -0
  19. package/dist/index.d.ts +18 -13
  20. package/dist/index.d.ts.map +1 -1
  21. package/dist/index.js +15 -24
  22. package/dist/index.js.map +1 -1
  23. package/dist/jwt-auth.d.ts +158 -57
  24. package/dist/jwt-auth.d.ts.map +1 -1
  25. package/dist/jwt-auth.js +447 -207
  26. package/dist/jwt-auth.js.map +1 -1
  27. package/dist/middleware.d.ts +476 -0
  28. package/dist/middleware.d.ts.map +1 -0
  29. package/dist/middleware.js +647 -0
  30. package/dist/middleware.js.map +1 -0
  31. package/dist/mimetypes.json +882 -1
  32. package/dist/misc.d.ts +268 -25
  33. package/dist/misc.d.ts.map +1 -1
  34. package/dist/misc.js +449 -168
  35. package/dist/misc.js.map +1 -1
  36. package/dist/openapi.d.ts +433 -0
  37. package/dist/openapi.d.ts.map +1 -0
  38. package/dist/openapi.js +624 -0
  39. package/dist/openapi.js.map +1 -0
  40. package/dist/router-types.d.ts +760 -0
  41. package/dist/router-types.d.ts.map +1 -0
  42. package/dist/router-types.js +23 -0
  43. package/dist/router-types.js.map +1 -0
  44. package/dist/router.d.ts +37 -201
  45. package/dist/router.d.ts.map +1 -1
  46. package/dist/router.js +502 -244
  47. package/dist/router.js.map +1 -1
  48. package/dist/static.d.ts +3 -3
  49. package/dist/static.d.ts.map +1 -1
  50. package/dist/static.js +164 -105
  51. package/dist/static.js.map +1 -1
  52. package/docs/THREAT_MODEL.md +52 -0
  53. package/docs/api-builder-v2-design.md +644 -0
  54. package/docs/api-builder-v3-design.md +397 -0
  55. package/docs/api-builder.md +454 -0
  56. package/docs/benchmark.md +27 -0
  57. package/docs/body-parsing.md +223 -0
  58. package/docs/errors.md +359 -0
  59. package/docs/expediate.png +0 -0
  60. package/docs/git.md +139 -0
  61. package/docs/jwt-auth.md +251 -0
  62. package/docs/logo.svg +12 -0
  63. package/docs/middleware.md +264 -0
  64. package/docs/openapi.md +180 -0
  65. package/docs/router.md +356 -0
  66. package/docs/static.md +128 -0
  67. package/docs/wiki.json +123 -0
  68. package/package.json +47 -8
  69. package/.npmignore +0 -16
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAoBA;;;GAGG;AAGH,OAAO,YAAY,MAAM,UAAU,CAAC;AACpC,OAAO,EAAE,YAAY,EAAE,CAAA;AACvB,YAAY,EACV,MAAM,EACN,aAAa,EACb,cAAc,EACd,UAAU,EACV,aAAa,EACb,YAAY,EACZ,KAAK,EACL,aAAa,EACb,UAAU,EACV,SAAS,GACV,MAAM,UAAU,CAAC;AAIlB,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AAClE,YAAY,EACV,aAAa,EACb,IAAI,EACL,MAAM,UAAU,CAAC;AAIlB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC3D,YAAY,EACV,WAAW,EACX,aAAa,EACb,QAAQ,GACT,MAAM,QAAQ,CAAC;AAGhB,OAAO,eAAe,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,eAAe,EAAE,CAAA;AAC1B,YAAY,EACV,SAAS,EACT,SAAS,EACV,MAAM,YAAY,CAAC;AAGpB,OAAQ,UAAU,MAAM,OAAO,CAAA;AAC/B,OAAO,EAAE,UAAU,EAAE,CAAA;AACrB,YAAY,EACR,iBAAiB,GACpB,MAAM,OAAO,CAAA;AAGd,OAAO,UAAU,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,UAAU,EAAE,CAAA;AACrB,YAAY,EACR,QAAQ,EACR,aAAa,EACb,eAAe,EACf,cAAc,EACd,QAAQ,EACR,iBAAiB,EACpB,MAAM,QAAQ,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAoBA;;;GAGG;AAGH,OAAO,YAAY,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,CAAA;AACvB,YAAY,EACV,MAAM,EACN,aAAa,EACb,aAAa,EACb,cAAc,EACd,UAAU,EACV,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,KAAK,EACL,SAAS,EACT,YAAY,EACZ,aAAa,EACb,UAAU,EACV,SAAS,GACV,MAAM,aAAa,CAAC;AAIrB,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACrE,YAAY,EACV,aAAa,EACb,IAAI,EACL,MAAM,aAAa,CAAC;AAIrB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAChI,YAAY,EACV,WAAW,EACX,eAAe,EACf,QAAQ,EACR,aAAa,EACb,QAAQ,EACR,cAAc,EACd,WAAW,GACZ,MAAM,WAAW,CAAC;AAGnB,OAAO,eAAe,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,YAAY,EACV,SAAS,EACT,SAAS,EACT,UAAU,EACV,kBAAkB,EAClB,YAAY,EACZ,UAAU,GACX,MAAM,eAAe,CAAC;AAGvB,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AACjD,YAAY,EACR,iBAAiB,GACpB,MAAM,UAAU,CAAC;AAGlB,OAAO,UAAU,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,CAAA;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,YAAY,EACR,QAAQ,EACR,aAAa,EACb,eAAe,EACf,cAAc,EACd,QAAQ,EACR,iBAAiB,EACjB,oBAAoB,EACpB,KAAK,EACL,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,mBAAmB,EACnB,UAAU,GACb,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACnF,YAAY,EACR,UAAU,EACV,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,aAAa,EACb,WAAW,EACX,UAAU,EACV,eAAe,GAClB,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtH,YAAY,EACV,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EACnB,WAAW,EACX,sBAAsB,GACvB,MAAM,iBAAiB,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- "use strict";
2
1
  /* Copyright 2021 Fabien Bavent
3
2
  *
4
3
  * Permission is hereby granted, free of charge, to any person obtaining a
@@ -23,33 +22,25 @@
23
22
  * @module expediate
24
23
  * TypeScript package for web server routing.
25
24
  */
26
- var __importDefault = (this && this.__importDefault) || function (mod) {
27
- return (mod && mod.__esModule) ? mod : { "default": mod };
28
- };
29
- Object.defineProperty(exports, "__esModule", { value: true });
30
- exports.apiBuilder = exports.gitHandler = exports.createJwtPlugin = exports.logger = exports.parseBody = exports.formData = exports.json = exports.mime = exports.sendFile = exports.serveFile = exports.serveStatic = exports.createRouter = void 0;
31
25
  // ── Router ────────────────────────────────────────────────────────────────────
32
- const router_1 = __importDefault(require("./router"));
33
- exports.createRouter = router_1.default;
26
+ import createRouter from './router.js';
27
+ export { createRouter };
34
28
  // ── Static ────────────────────────────────────────────────────────────────────
35
- var static_1 = require("./static");
36
- Object.defineProperty(exports, "serveStatic", { enumerable: true, get: function () { return static_1.serveStatic; } });
37
- Object.defineProperty(exports, "serveFile", { enumerable: true, get: function () { return static_1.serveFile; } });
38
- Object.defineProperty(exports, "sendFile", { enumerable: true, get: function () { return static_1.sendFile; } });
39
- Object.defineProperty(exports, "mime", { enumerable: true, get: function () { return static_1.mime; } });
29
+ export { serveStatic, serveFile, sendFile, mime } from './static.js';
40
30
  // ── Miscallenous ──────────────────────────────────────────────────────────────
41
- var misc_1 = require("./misc");
42
- Object.defineProperty(exports, "json", { enumerable: true, get: function () { return misc_1.json; } });
43
- Object.defineProperty(exports, "formData", { enumerable: true, get: function () { return misc_1.formData; } });
44
- Object.defineProperty(exports, "parseBody", { enumerable: true, get: function () { return misc_1.parseBody; } });
45
- Object.defineProperty(exports, "logger", { enumerable: true, get: function () { return misc_1.logger; } });
31
+ export { json, formData, formEncoded, raw, text, parseBody, logger, cors, streamFormData, parseMultipartBody } from './misc.js';
46
32
  // ── JWT Authentication ────────────────────────────────────────────────────────
47
- const jwt_auth_1 = __importDefault(require("./jwt-auth"));
48
- exports.createJwtPlugin = jwt_auth_1.default;
33
+ import createJwtPlugin from './jwt-auth.js';
34
+ export { createJwtPlugin };
35
+ export { createMapTokenStore } from './jwt-auth.js';
49
36
  // ── Git repository ────────────────────────────────────────────────────────────
50
- const git_1 = __importDefault(require("./git"));
51
- exports.gitHandler = git_1.default;
37
+ export { gitHandler, gitCreate } from './git.js';
52
38
  // ── API Service ───────────────────────────────────────────────────────────────
53
- const apis_1 = __importDefault(require("./apis"));
54
- exports.apiBuilder = apis_1.default;
39
+ import apiBuilder from './apis.js';
40
+ export { apiBuilder };
41
+ export { defineController } from './apis.js';
42
+ // ── OpenAPI spec generation ───────────────────────────────────────────────────
43
+ export { describe, openApiSpec, serializeSpec, DESCRIBE_META } from './openapi.js';
44
+ // ── Middleware ────────────────────────────────────────────────────────────────
45
+ export { compress, requestId, rateLimit, cacheControl, csrf, securityHeaders, conditionalGet } from './middleware.js';
55
46
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH;;;GAGG;;;;;;AAEH,iFAAiF;AACjF,sDAAoC;AAC3B,uBADF,gBAAY,CACE;AAcrB,iFAAiF;AAEjF,mCAAkE;AAAzD,qGAAA,WAAW,OAAA;AAAE,mGAAA,SAAS,OAAA;AAAE,kGAAA,QAAQ,OAAA;AAAE,8FAAA,IAAI,OAAA;AAM/C,iFAAiF;AAEjF,+BAA2D;AAAlD,4FAAA,IAAI,OAAA;AAAE,gGAAA,QAAQ,OAAA;AAAE,iGAAA,SAAS,OAAA;AAAE,8FAAA,MAAM,OAAA;AAO1C,iFAAiF;AACjF,0DAAwC;AAC/B,0BADF,kBAAe,CACE;AAMxB,iFAAiF;AACjF,gDAA+B;AACtB,qBADD,aAAU,CACC;AAKnB,iFAAiF;AACjF,kDAA+B;AACtB,qBADF,cAAU,CACE"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AACH;;;GAGG;AAEH,iFAAiF;AACjF,OAAO,YAAY,MAAM,aAAa,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,CAAA;AAmBvB,iFAAiF;AAEjF,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AAMrE,iFAAiF;AAEjF,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAWhI,iFAAiF;AACjF,OAAO,eAAe,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,eAAe,EAAE,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAUpD,iFAAiF;AACjF,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAKjD,iFAAiF;AACjF,OAAO,UAAU,MAAM,WAAW,CAAC;AACnC,OAAO,EAAE,UAAU,EAAE,CAAA;AACrB,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAiB7C,iFAAiF;AACjF,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAiBnF,iFAAiF;AACjF,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC"}
@@ -4,20 +4,35 @@
4
4
  * JWT authentication plugin for the Expediate router.
5
5
  *
6
6
  * Provides:
7
- * - Stateless access tokens (HS256 / HS384 / HS512 HMAC-signed JWTs).
8
- * - Opaque refresh tokens with server-side storage and automatic rotation.
7
+ * - Stateless access tokens signed with HS256/HS384/HS512 (shared secret) or
8
+ * RS256/RS384/RS512/ES256/ES384/ES512 (asymmetric PEM key pairs).
9
+ * - Signed JWT refresh tokens with JTI-based server-side revocation.
9
10
  * - Route handlers for login, token refresh, and logout.
10
11
  * - Middleware for token validation, authorisation, role checks, and
11
12
  * permission checks.
13
+ * - A `createMapTokenStore()` factory for in-process token storage.
12
14
  *
13
15
  * Security notes:
14
16
  * - Passwords are hashed with SHA-256 for demonstration purposes only.
15
17
  * Replace with bcrypt / argon2 in production.
16
18
  * - The default secrets are placeholders — always override them in production.
17
- * - Refresh token storage defaults to an in-process Map; replace with a
18
- * persistent store (Redis, database) for multi-instance deployments.
19
+ * - `createMapTokenStore()` is an in-process store; replace with a Redis or
20
+ * database adapter for multi-instance deployments.
21
+ * - Refresh tokens are only issued when `refreshTokenStore` is configured.
22
+ * Absence of a store disables refresh-token support entirely.
19
23
  */
20
24
  import type { Middleware } from './router.js';
25
+ declare module './router.js' {
26
+ interface RouterRequest {
27
+ /**
28
+ * The decoded access-token payload for the authenticated user, set by the
29
+ * JWT plugin's {@link JwtPlugin.authenticate} middleware (and cleared at the
30
+ * start of each `authenticate` run). `undefined` when the request is
31
+ * unauthenticated.
32
+ */
33
+ user?: TokenPayload;
34
+ }
35
+ }
21
36
  /** A user record as stored in (or returned by) the user database. */
22
37
  export interface UserRecord {
23
38
  /** Stable unique identifier (used as JWT `sub` claim when present). */
@@ -28,7 +43,7 @@ export interface UserRecord {
28
43
  * SHA-256 hex digest of the user's password.
29
44
  * Replace with a bcrypt/argon2 hash in production.
30
45
  */
31
- passwordHash: string;
46
+ passwordHash?: string;
32
47
  /** Role labels assigned to this user (e.g. `'admin'`, `'editor'`). */
33
48
  roles?: string[];
34
49
  /**
@@ -41,13 +56,13 @@ export interface UserRecord {
41
56
  }
42
57
  /**
43
58
  * The decoded JWT access-token payload attached to `req.user` after
44
- * successful authentication.
59
+ * successful authentication. The `sub` claim identifies the user (typically
60
+ * the username or a stable user ID). Custom claims returned by
61
+ * `config.payload` are carried in the index-signature field.
45
62
  */
46
63
  export interface TokenPayload {
47
- /** JWT subject — typically the user's stable ID. */
64
+ /** JWT subject — the user identifier (username or stable ID). */
48
65
  sub: string;
49
- /** Username extracted from the user record. */
50
- username: string;
51
66
  /** Issuer claim, set to `config.issuer`. */
52
67
  iss: string;
53
68
  /** Issued-at timestamp (Unix seconds). */
@@ -61,41 +76,99 @@ export interface TokenPayload {
61
76
  /** Any additional claims produced by `config.payload`. */
62
77
  [key: string]: unknown;
63
78
  }
64
- /** Internal metadata stored alongside each active refresh token. */
65
- interface RefreshTokenData {
66
- /** Username the refresh token was issued to. */
67
- username: string;
68
- /** Unix ms timestamp of issuance. */
79
+ /**
80
+ * Metadata stored in the token store for each active refresh token.
81
+ * The key used to address this record is the token's `jti` (JWT ID) claim.
82
+ */
83
+ export interface RefreshTokenRecord {
84
+ /** Subject the refresh token was issued to (`sub` from the access token). */
85
+ sub: string;
86
+ /** Unix millisecond timestamp of issuance. */
69
87
  issuedAt: number;
70
- /** Unix ms timestamp after which the token must be rejected. */
88
+ /** Unix millisecond timestamp after which the token must be rejected. */
71
89
  expiresAt: number;
72
90
  }
73
91
  /**
74
- * Minimal interface for the refresh-token store.
75
- * Any object implementing these four methods is accepted (Map, Redis client
76
- * adapter, database wrapper, etc.).
92
+ * Async-compatible interface for the refresh-token store.
93
+ *
94
+ * The store is addressed by JWT ID (`jti`) — a UUID v4 unique to each
95
+ * issued refresh token. Every method may return its result either directly
96
+ * or as a Promise, enabling both synchronous (Map) and asynchronous (Redis,
97
+ * database) implementations.
98
+ *
99
+ * Cleanup of expired records is the store's responsibility. The built-in
100
+ * {@link createMapTokenStore} performs lazy cleanup on `get()`.
77
101
  */
78
102
  export interface TokenStore {
79
- set(key: string, value: RefreshTokenData): void;
80
- get(key: string): RefreshTokenData | undefined;
81
- delete(key: string): void;
82
- has(key: string): boolean;
103
+ /**
104
+ * Persist a new refresh-token record.
105
+ * @param jti - Unique JWT ID of the issued refresh token.
106
+ * @param record - Metadata to store alongside the token.
107
+ */
108
+ set(jti: string, record: RefreshTokenRecord): void | Promise<void>;
109
+ /**
110
+ * Retrieve the record for a given JTI, or `undefined` if not found or
111
+ * expired. Implementations are encouraged to delete expired records lazily
112
+ * here rather than in a background job.
113
+ * @param jti - JWT ID to look up.
114
+ */
115
+ get(jti: string): RefreshTokenRecord | undefined | Promise<RefreshTokenRecord | undefined>;
116
+ /**
117
+ * Remove a single record by JTI. Idempotent — deleting a non-existent
118
+ * key is not an error.
119
+ * @param jti - JWT ID to remove.
120
+ */
121
+ delete(jti: string): void | Promise<void>;
122
+ /**
123
+ * Revoke **all** refresh tokens belonging to a given subject (user).
124
+ * Optional — when absent, per-JTI revocation still works but bulk logout
125
+ * ("log out all sessions") is not available.
126
+ * @param sub - The subject identifier to revoke tokens for.
127
+ */
128
+ deleteBySubject?(sub: string): void | Promise<void>;
83
129
  }
84
130
  /**
85
- * Supported HMAC-SHA signing algorithms for JWT.
86
- * RS*, ES*, and PS* families are not yet implemented.
131
+ * Supported JWT signing algorithms.
132
+ *
133
+ * - **HS256 / HS384 / HS512** — HMAC-SHA family. Uses a shared secret string
134
+ * (`accessTokenSecret` / `refreshTokenSecret`).
135
+ * - **RS256 / RS384 / RS512** — RSA PKCS#1 v1.5 + SHA family. Requires PEM
136
+ * private key for signing and PEM public key for verification.
137
+ * - **ES256 / ES384 / ES512** — ECDSA + SHA family. Requires a PEM private
138
+ * key (P-256 / P-384 / P-521 curve respectively) for signing and the
139
+ * corresponding PEM public key for verification. Signatures are encoded in
140
+ * the compact IEEE P1363 (JOSE) format rather than ASN.1 DER.
87
141
  */
88
- export type JwtAlgorithm = 'HS256' | 'HS384' | 'HS512';
142
+ export type JwtAlgorithm = 'HS256' | 'HS384' | 'HS512' | 'RS256' | 'RS384' | 'RS512' | 'ES256' | 'ES384' | 'ES512';
89
143
  /**
90
144
  * Full configuration object for {@link createJwtPlugin}.
91
- * All fields have defaults; override only what you need.
145
+ * All fields except `accessTokenSecret` and `refreshTokenSecret` have defaults.
92
146
  */
93
147
  export interface JwtConfig {
94
- /** HMAC secret used to sign access tokens. **Change in production.** */
148
+ /** HMAC secret used to sign access tokens (HS* algorithms). **Change in production.** */
95
149
  accessTokenSecret: string;
96
- /** HMAC secret used to sign refresh tokens (currently unused refresh *
97
- * tokens are opaque random strings, not JWTs). Reserved for future use. */
150
+ /** HMAC secret used to sign refresh tokens (HS* algorithms). **Change in production.** */
98
151
  refreshTokenSecret: string;
152
+ /**
153
+ * PEM-encoded **private** key used to sign access tokens (RS* / ES* algorithms).
154
+ * Required when `alg` is RS* or ES*.
155
+ */
156
+ accessTokenPrivateKey?: string;
157
+ /**
158
+ * PEM-encoded **public** key used to verify access tokens (RS* / ES* algorithms).
159
+ * Required when `alg` is RS* or ES*.
160
+ */
161
+ accessTokenPublicKey?: string;
162
+ /**
163
+ * PEM-encoded **private** key used to sign refresh tokens (RS* / ES* algorithms).
164
+ * Falls back to `accessTokenPrivateKey` when absent.
165
+ */
166
+ refreshTokenPrivateKey?: string;
167
+ /**
168
+ * PEM-encoded **public** key used to verify refresh tokens (RS* / ES* algorithms).
169
+ * Falls back to `accessTokenPublicKey` when absent.
170
+ */
171
+ refreshTokenPublicKey?: string;
99
172
  /** Access token lifetime in **seconds**. Defaults to 15 minutes. */
100
173
  accessTokenExpiry: number;
101
174
  /** Refresh token lifetime in **seconds**. Defaults to 7 days. */
@@ -112,14 +185,15 @@ export interface JwtConfig {
112
185
  alg: JwtAlgorithm;
113
186
  /**
114
187
  * Extract the login username from a user record.
188
+ * Used as the fallback `sub` claim when `payload()` does not set one.
115
189
  * Defaults to `(user) => user.username`.
116
190
  */
117
191
  username: (user: UserRecord) => string;
118
192
  /**
119
- * Fetch a user record by username.
193
+ * Fetch a user record by subject (username or stable ID).
120
194
  * Return `undefined` (or any falsy value) when the user does not exist.
121
195
  */
122
- fetchUser: (username: string) => UserRecord | undefined;
196
+ fetchUser: (sub: string) => UserRecord | undefined | Promise<UserRecord | undefined>;
123
197
  /**
124
198
  * Return `true` when the supplied plain-text `password` is valid for
125
199
  * `user`, `false` otherwise.
@@ -127,19 +201,23 @@ export interface JwtConfig {
127
201
  * The default implementation compares SHA-256 hashes; replace with a
128
202
  * timing-safe bcrypt/argon2 check in production.
129
203
  */
130
- isPasswordValid: (user: UserRecord, password: string) => boolean;
204
+ isPasswordValid: (user: UserRecord, password: string) => boolean | Promise<boolean>;
131
205
  /**
132
- * Build the JWT payload for a user.
133
- * The `iss`, `iat`, `exp`, and `sub` claims are added automatically.
134
- * Returning a partial object is fine the plugin merges the rest.
206
+ * Build the JWT access-token payload for a user.
207
+ * The `iss`, `iat`, and `exp` claims are added automatically.
208
+ * When `sub` is absent from the returned object, `config.username(user)`
209
+ * is used as the fallback.
135
210
  */
136
- payload: (user: UserRecord) => Partial<TokenPayload>;
211
+ payload: (user: UserRecord) => Partial<TokenPayload> | Promise<Partial<TokenPayload>>;
137
212
  /**
138
- * Active refresh-token store.
139
- * Defaults to an in-process `Map` (lost on restart; not suitable for
140
- * multi-instance deployments).
213
+ * Refresh-token store. When absent, refresh tokens are **not** issued:
214
+ * `POST /auth/login` omits `refreshToken` from its response, and
215
+ * `POST /auth/refresh` responds with `501 Not Implemented`.
216
+ *
217
+ * Use {@link createMapTokenStore} for a simple in-process store, or supply
218
+ * a custom adapter that implements {@link TokenStore}.
141
219
  */
142
- refreshTokenStore: TokenStore;
220
+ refreshTokenStore?: TokenStore;
143
221
  }
144
222
  /** Result returned by {@link verifyToken}. */
145
223
  type VerifyResult = {
@@ -167,38 +245,48 @@ export declare function hashPassword(password: string): string;
167
245
  * Replace or ignore this map entirely when you supply your own `fetchUser`.
168
246
  */
169
247
  export declare const userDatabase: Map<string, UserRecord>;
248
+ /**
249
+ * Create an in-process {@link TokenStore} backed by a `Map`.
250
+ *
251
+ * Expired records are cleaned up lazily on `get()` — no background timer is
252
+ * needed. This store is **not** suitable for multi-instance deployments
253
+ * because it is local to the current Node.js process. Replace with a Redis
254
+ * or database adapter for production use.
255
+ *
256
+ * @returns A new {@link TokenStore} instance.
257
+ */
258
+ export declare function createMapTokenStore(): TokenStore;
170
259
  /**
171
260
  * Sign a payload object and return a compact JWT string.
172
261
  *
173
- * Automatically adds the `iat` (issued-at) and `exp` (expiration) claims.
174
- * Any claims already present in `payload` are preserved and take precedence
175
- * over `iat`/`exp` (use this to override expiry if needed).
262
+ * Automatically adds the `iat` (issued-at) and `exp` (expiration) claims,
263
+ * overriding any values already present in `payload`.
176
264
  *
177
265
  * @param payload - JWT payload claims (must be JSON-serialisable).
178
- * @param secret - HMAC secret used to sign the token.
266
+ * @param key - HMAC secret (HS*) or PEM private key (RS* / ES*).
179
267
  * @param expiresIn - Validity window in **seconds** from the current time.
180
268
  * @param alg - Signing algorithm. Defaults to `'HS256'`.
181
269
  * @returns A compact JWT string in the form `header.payload.signature`.
182
270
  */
183
- declare function signToken(payload: Partial<TokenPayload>, secret: string, expiresIn: number, alg?: JwtAlgorithm): string;
271
+ declare function signToken(payload: Partial<TokenPayload>, key: string, expiresIn: number, alg?: JwtAlgorithm): string;
184
272
  /**
185
273
  * Verify a compact JWT string and return its decoded payload on success.
186
274
  *
187
275
  * Performs the following checks in order:
188
276
  * 1. Structural validity (exactly three dot-separated segments).
189
277
  * 2. Algorithm consistency (header `alg` matches the expected `alg`).
190
- * 3. Signature integrity (timing-safe HMAC comparison).
278
+ * 3. Signature integrity.
191
279
  * 4. Expiration (`exp` claim is in the future).
192
280
  *
193
281
  * All errors are returned as `{ valid: false, error }` — no exception is
194
282
  * thrown to the caller.
195
283
  *
196
- * @param token - The compact JWT string to verify.
197
- * @param secret - HMAC secret that was used to sign the token.
198
- * @param alg - Expected signing algorithm.
284
+ * @param token - The compact JWT string to verify.
285
+ * @param key - HMAC secret (HS*) or PEM public key (RS* / ES*).
286
+ * @param alg - Expected signing algorithm.
199
287
  * @returns A {@link VerifyResult} discriminated union.
200
288
  */
201
- declare function verifyToken(token: string, secret: string, alg: JwtAlgorithm): VerifyResult;
289
+ declare function verifyToken(token: string, key: string, alg: JwtAlgorithm): VerifyResult;
202
290
  /**
203
291
  * The object returned by {@link createJwtPlugin}.
204
292
  *
@@ -206,7 +294,13 @@ declare function verifyToken(token: string, secret: string, alg: JwtAlgorithm):
206
294
  * routes:
207
295
  *
208
296
  * ```ts
209
- * const auth = createJwtPlugin({ accessTokenSecret: process.env.JWT_SECRET! });
297
+ * import { createRouter, json, createJwtPlugin, createMapTokenStore } from 'expediate';
298
+ *
299
+ * const auth = createJwtPlugin({
300
+ * accessTokenSecret: process.env.JWT_ACCESS_SECRET!,
301
+ * refreshTokenSecret: process.env.JWT_REFRESH_SECRET!,
302
+ * refreshTokenStore: createMapTokenStore(),
303
+ * });
210
304
  *
211
305
  * app.post('/auth/login', json(), auth.login);
212
306
  * app.post('/auth/refresh', json(), auth.refresh);
@@ -221,19 +315,21 @@ export interface JwtPlugin {
221
315
  /**
222
316
  * Route handler for `POST /auth/login`.
223
317
  * Expects a JSON body with `{ username, password }`.
224
- * On success: responds with `{ accessToken, refreshToken, expiresIn, tokenType }`.
318
+ * On success: responds with `{ accessToken, expiresIn, tokenType }`.
319
+ * When a `refreshTokenStore` is configured, also includes `{ refreshToken }`.
225
320
  */
226
321
  login: Middleware;
227
322
  /**
228
323
  * Route handler for `POST /auth/refresh`.
229
- * Expects a JSON body with `{ username, refreshToken }`.
324
+ * Expects a JSON body with `{ refreshToken }`.
325
+ * Returns `501` when no `refreshTokenStore` is configured.
230
326
  * On success: responds with a new `{ accessToken, refreshToken, ... }` pair.
231
327
  */
232
328
  refresh: Middleware;
233
329
  /**
234
330
  * Route handler for `POST /auth/logout`.
235
331
  * Expects a JSON body with `{ refreshToken }` (optional).
236
- * Always responds with 200; revokes the refresh token if provided.
332
+ * Always responds with 200; revokes the refresh token if provided and valid.
237
333
  */
238
334
  logout: Middleware;
239
335
  /**
@@ -267,12 +363,17 @@ export interface JwtPlugin {
267
363
  /**
268
364
  * Create a JWT authentication plugin pre-configured with the given options.
269
365
  *
270
- * All config fields have safe defaults for development. At minimum, set
271
- * `accessTokenSecret` (and `refreshTokenSecret` if you plan to use it) to
272
- * random values in production.
366
+ * For **asymmetric algorithms** (RS* / ES*) you must provide at minimum
367
+ * `accessTokenPrivateKey` and `accessTokenPublicKey` in addition to setting
368
+ * `alg`. The refresh-token keys fall back to the access-token keys when
369
+ * `refreshTokenPrivateKey` / `refreshTokenPublicKey` are not set.
370
+ *
371
+ * Refresh tokens are only issued when `refreshTokenStore` is provided.
372
+ * Use {@link createMapTokenStore} for a simple in-process store.
273
373
  *
274
374
  * @param userConfig - Partial {@link JwtConfig} overrides.
275
375
  * @returns A {@link JwtPlugin} object exposing handlers and middleware.
376
+ * @throws {Error} When `alg` is RS* or ES* but the required PEM keys are absent.
276
377
  */
277
378
  export declare function createJwtPlugin(userConfig?: Partial<JwtConfig>): JwtPlugin;
278
379
  export default createJwtPlugin;
@@ -1 +1 @@
1
- {"version":3,"file":"jwt-auth.d.ts","sourceRoot":"","sources":["../src/jwt-auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"jwt-auth.d.ts","sourceRoot":"","sources":["../src/jwt-auth.ts"],"names":[],"mappings":"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"}