@bonapasogit-dev/jwt-manager 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 ADDED
@@ -0,0 +1,234 @@
1
+ # @bonapasogit-dev/jwt-manager
2
+
3
+ High-performance JWT lifecycle management library with JTI validation for preventing replay attacks and enabling token revocation.
4
+
5
+ ## Features
6
+
7
+ - ✅ **JTI Validation** - Unique token IDs using ULID for collision-free identification
8
+ - ✅ **Token Revocation** - Blacklist tokens before expiry
9
+ - ✅ **One-Time Tokens** - Single-use tokens with automatic invalidation
10
+ - ✅ **Security-First** - Enforces `aud`, `iss`, `exp` claims on all tokens
11
+ - ✅ **Multiple Algorithms** - RS256, ES256, HS256, and more
12
+ - ✅ **TypeScript** - Full type safety with comprehensive types
13
+
14
+ ## Installation
15
+
16
+ ```bash
17
+ npm install @bonapasogit-dev/jwt-manager
18
+ ```
19
+
20
+ ## Quick Start
21
+
22
+ ### Using HMAC (HS256)
23
+
24
+ ```typescript
25
+ import { createJwtManager } from '@bonapasogit-dev/jwt-manager';
26
+
27
+ const jwtManager = createJwtManager({
28
+ algorithm: 'HS256',
29
+ secret: 'your-secret-key-min-32-characters-long',
30
+ });
31
+
32
+ // Sign a token
33
+ const token = jwtManager.sign({
34
+ subject: 'user-123',
35
+ audience: 'my-app',
36
+ issuer: 'auth-service',
37
+ expiresIn: 3600, // 1 hour
38
+ claims: {
39
+ role: 'admin',
40
+ },
41
+ });
42
+
43
+ // Verify a token
44
+ const result = await jwtManager.verify(token);
45
+ console.log(result.payload.sub); // 'user-123'
46
+ console.log(result.payload.jti); // ULID (e.g., '01ARZ3NDEKTSV4RRFFQ69DT1FK')
47
+ ```
48
+
49
+ ### Using RSA (RS256) - Recommended for Production
50
+
51
+ ```typescript
52
+ import { createJwtManager } from '@bonapasogit-dev/jwt-manager';
53
+ import fs from 'fs';
54
+
55
+ const jwtManager = createJwtManager({
56
+ algorithm: 'RS256',
57
+ privateKey: fs.readFileSync('./private.pem', 'utf-8'),
58
+ publicKey: fs.readFileSync('./public.pem', 'utf-8'),
59
+ });
60
+ ```
61
+
62
+ ## Token Revocation
63
+
64
+ Revoke tokens before their natural expiry:
65
+
66
+ ```typescript
67
+ // Revoke by JTI
68
+ const payload = jwtManager.decode(token);
69
+ await jwtManager.revoke(payload.jti, payload.exp);
70
+
71
+ // Or revoke directly from token
72
+ await jwtManager.revokeToken(token);
73
+
74
+ // Verification will now fail
75
+ try {
76
+ await jwtManager.verify(token);
77
+ } catch (error) {
78
+ if (error instanceof JwtRevokedError) {
79
+ console.log('Token has been revoked');
80
+ }
81
+ }
82
+ ```
83
+
84
+ ## One-Time Tokens
85
+
86
+ Create tokens that can only be used once (e.g., for password reset):
87
+
88
+ ```typescript
89
+ const oneTimeToken = jwtManager.sign({
90
+ subject: 'user-123',
91
+ audience: 'password-reset',
92
+ issuer: 'auth-service',
93
+ expiresIn: 900, // 15 minutes
94
+ oneTimeToken: true,
95
+ });
96
+
97
+ // First verification succeeds
98
+ const result = await jwtManager.verify(oneTimeToken);
99
+
100
+ // Second verification throws JwtReplayError
101
+ try {
102
+ await jwtManager.verify(oneTimeToken);
103
+ } catch (error) {
104
+ if (error instanceof JwtReplayError) {
105
+ console.log('Token already used');
106
+ }
107
+ }
108
+ ```
109
+
110
+ ## Custom Token Store
111
+
112
+ For distributed systems, implement the `TokenStore` interface with Redis or PostgreSQL:
113
+
114
+ ```typescript
115
+ import { TokenStore, createJwtManager } from '@bonapasogit-dev/jwt-manager';
116
+ import Redis from 'ioredis';
117
+
118
+ class RedisTokenStore implements TokenStore {
119
+ private redis: Redis;
120
+
121
+ constructor(redis: Redis) {
122
+ this.redis = redis;
123
+ }
124
+
125
+ async add(jti: string, expiresAt: number): Promise<void> {
126
+ const ttl = expiresAt - Math.floor(Date.now() / 1000);
127
+ if (ttl > 0) {
128
+ await this.redis.setex(`jwt:revoked:${jti}`, ttl, '1');
129
+ }
130
+ }
131
+
132
+ async has(jti: string): Promise<boolean> {
133
+ const exists = await this.redis.exists(`jwt:revoked:${jti}`);
134
+ return exists === 1;
135
+ }
136
+
137
+ async remove(jti: string): Promise<void> {
138
+ await this.redis.del(`jwt:revoked:${jti}`);
139
+ }
140
+
141
+ async cleanup(): Promise<void> {
142
+ // Redis handles TTL automatically
143
+ }
144
+ }
145
+
146
+ const jwtManager = createJwtManager({
147
+ algorithm: 'RS256',
148
+ privateKey: '...',
149
+ publicKey: '...',
150
+ tokenStore: new RedisTokenStore(new Redis()),
151
+ });
152
+ ```
153
+
154
+ ## Error Handling
155
+
156
+ ```typescript
157
+ import {
158
+ JwtExpiredError,
159
+ JwtRevokedError,
160
+ JwtReplayError,
161
+ JwtInvalidSignatureError,
162
+ JwtInvalidClaimsError,
163
+ JwtMalformedError,
164
+ isJwtError,
165
+ JwtErrorCode,
166
+ } from '@bonapasogit-dev/jwt-manager';
167
+
168
+ try {
169
+ const result = await jwtManager.verify(token);
170
+ } catch (error) {
171
+ if (isJwtError(error)) {
172
+ switch (error.code) {
173
+ case JwtErrorCode.EXPIRED:
174
+ // Token has expired
175
+ break;
176
+ case JwtErrorCode.REVOKED:
177
+ // Token was revoked
178
+ break;
179
+ case JwtErrorCode.REPLAY:
180
+ // One-time token already used
181
+ break;
182
+ case JwtErrorCode.INVALID_SIGNATURE:
183
+ // Signature verification failed
184
+ break;
185
+ case JwtErrorCode.INVALID_CLAIMS:
186
+ // Missing or invalid claims
187
+ break;
188
+ case JwtErrorCode.MALFORMED:
189
+ // Token cannot be decoded
190
+ break;
191
+ }
192
+ }
193
+ }
194
+ ```
195
+
196
+ ## API Reference
197
+
198
+ ### `JwtManager`
199
+
200
+ #### `sign(options: SignOptions): string`
201
+
202
+ Generate a JWT with auto-injected `jti`, `iat`, `exp` claims.
203
+
204
+ #### `verify(token: string, options?: VerifyOptions): Promise<VerifyResult>`
205
+
206
+ Verify a JWT's signature, expiry, and JTI status.
207
+
208
+ #### `revoke(jti: string, expiresAt: number): Promise<void>`
209
+
210
+ Add a JTI to the denylist.
211
+
212
+ #### `revokeToken(token: string): Promise<void>`
213
+
214
+ Revoke a token by decoding and extracting its JTI.
215
+
216
+ #### `decode(token: string): JwtPayload | null`
217
+
218
+ Decode without verification (for inspection only).
219
+
220
+ #### `isRevoked(jti: string): Promise<boolean>`
221
+
222
+ Check if a JTI has been revoked.
223
+
224
+ ## Security Best Practices
225
+
226
+ 1. **Use Asymmetric Algorithms** - RS256/ES256 for shared environments
227
+ 2. **Rotate Keys Regularly** - Every 24-48 hours for production
228
+ 3. **Keep Secrets Secure** - Use environment variables or secret managers
229
+ 4. **Set Reasonable Expiry** - Balance security with user experience
230
+ 5. **Implement Token Refresh** - Short-lived access tokens + long-lived refresh tokens
231
+
232
+ ## License
233
+
234
+ MIT
@@ -0,0 +1,78 @@
1
+ import { JwtErrorCode } from './types';
2
+ /**
3
+ * Base error class for all JWT-related errors.
4
+ */
5
+ export declare abstract class JwtError extends Error {
6
+ abstract readonly code: JwtErrorCode;
7
+ constructor(message: string);
8
+ /**
9
+ * Convert error to a structured object for logging/API responses.
10
+ */
11
+ toJSON(): {
12
+ code: JwtErrorCode;
13
+ message: string;
14
+ name: string;
15
+ };
16
+ }
17
+ /**
18
+ * Token has expired (exp claim is in the past).
19
+ */
20
+ export declare class JwtExpiredError extends JwtError {
21
+ readonly code = JwtErrorCode.EXPIRED;
22
+ readonly expiredAt: Date;
23
+ constructor(expiredAt: Date);
24
+ }
25
+ /**
26
+ * Token has been revoked (JTI found in denylist).
27
+ */
28
+ export declare class JwtRevokedError extends JwtError {
29
+ readonly code = JwtErrorCode.REVOKED;
30
+ readonly jti: string;
31
+ constructor(jti: string);
32
+ }
33
+ /**
34
+ * One-time token has already been used (replay attack detected).
35
+ */
36
+ export declare class JwtReplayError extends JwtError {
37
+ readonly code = JwtErrorCode.REPLAY;
38
+ readonly jti: string;
39
+ constructor(jti: string);
40
+ }
41
+ /**
42
+ * Token signature is invalid.
43
+ */
44
+ export declare class JwtInvalidSignatureError extends JwtError {
45
+ readonly code = JwtErrorCode.INVALID_SIGNATURE;
46
+ constructor();
47
+ }
48
+ /**
49
+ * Token claims validation failed (missing or invalid aud, iss, etc).
50
+ */
51
+ export declare class JwtInvalidClaimsError extends JwtError {
52
+ readonly code = JwtErrorCode.INVALID_CLAIMS;
53
+ readonly claim: string;
54
+ constructor(claim: string, reason: string);
55
+ }
56
+ /**
57
+ * Token is malformed or cannot be decoded.
58
+ */
59
+ export declare class JwtMalformedError extends JwtError {
60
+ readonly code = JwtErrorCode.MALFORMED;
61
+ constructor(reason?: string);
62
+ }
63
+ /**
64
+ * Type guard to check if an error is a JwtError.
65
+ */
66
+ export declare function isJwtError(error: unknown): error is JwtError;
67
+ /**
68
+ * Map of error codes to error classes for programmatic handling.
69
+ */
70
+ export declare const JwtErrors: {
71
+ readonly JwtExpiredError: typeof JwtExpiredError;
72
+ readonly JwtRevokedError: typeof JwtRevokedError;
73
+ readonly JwtReplayError: typeof JwtReplayError;
74
+ readonly JwtInvalidSignatureError: typeof JwtInvalidSignatureError;
75
+ readonly JwtInvalidClaimsError: typeof JwtInvalidClaimsError;
76
+ readonly JwtMalformedError: typeof JwtMalformedError;
77
+ };
78
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC;;GAEG;AACH,8BAAsB,QAAS,SAAQ,KAAK;IACxC,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;gBAEzB,OAAO,EAAE,MAAM;IAM3B;;OAEG;IACH,MAAM,IAAI;QAAE,IAAI,EAAE,YAAY,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE;CAOlE;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,QAAQ;IACzC,QAAQ,CAAC,IAAI,wBAAwB;IACrC,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;gBAEb,SAAS,EAAE,IAAI;CAI9B;AAED;;GAEG;AACH,qBAAa,eAAgB,SAAQ,QAAQ;IACzC,QAAQ,CAAC,IAAI,wBAAwB;IACrC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;gBAET,GAAG,EAAE,MAAM;CAI1B;AAED;;GAEG;AACH,qBAAa,cAAe,SAAQ,QAAQ;IACxC,QAAQ,CAAC,IAAI,uBAAuB;IACpC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;gBAET,GAAG,EAAE,MAAM;CAI1B;AAED;;GAEG;AACH,qBAAa,wBAAyB,SAAQ,QAAQ;IAClD,QAAQ,CAAC,IAAI,kCAAkC;;CAKlD;AAED;;GAEG;AACH,qBAAa,qBAAsB,SAAQ,QAAQ;IAC/C,QAAQ,CAAC,IAAI,+BAA+B;IAC5C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAEX,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAI5C;AAED;;GAEG;AACH,qBAAa,iBAAkB,SAAQ,QAAQ;IAC3C,QAAQ,CAAC,IAAI,0BAA0B;gBAE3B,MAAM,CAAC,EAAE,MAAM;CAG9B;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,QAAQ,CAE5D;AAED;;GAEG;AACH,eAAO,MAAM,SAAS;;;;;;;CAOZ,CAAC"}
package/dist/errors.js ADDED
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JwtErrors = exports.JwtMalformedError = exports.JwtInvalidClaimsError = exports.JwtInvalidSignatureError = exports.JwtReplayError = exports.JwtRevokedError = exports.JwtExpiredError = exports.JwtError = void 0;
4
+ exports.isJwtError = isJwtError;
5
+ const types_1 = require("./types");
6
+ /**
7
+ * Base error class for all JWT-related errors.
8
+ */
9
+ class JwtError extends Error {
10
+ constructor(message) {
11
+ super(message);
12
+ this.name = this.constructor.name;
13
+ Error.captureStackTrace(this, this.constructor);
14
+ }
15
+ /**
16
+ * Convert error to a structured object for logging/API responses.
17
+ */
18
+ toJSON() {
19
+ return {
20
+ code: this.code,
21
+ message: this.message,
22
+ name: this.name,
23
+ };
24
+ }
25
+ }
26
+ exports.JwtError = JwtError;
27
+ /**
28
+ * Token has expired (exp claim is in the past).
29
+ */
30
+ class JwtExpiredError extends JwtError {
31
+ constructor(expiredAt) {
32
+ super(`Token expired at ${expiredAt.toISOString()}`);
33
+ this.code = types_1.JwtErrorCode.EXPIRED;
34
+ this.expiredAt = expiredAt;
35
+ }
36
+ }
37
+ exports.JwtExpiredError = JwtExpiredError;
38
+ /**
39
+ * Token has been revoked (JTI found in denylist).
40
+ */
41
+ class JwtRevokedError extends JwtError {
42
+ constructor(jti) {
43
+ super(`Token with JTI "${jti}" has been revoked`);
44
+ this.code = types_1.JwtErrorCode.REVOKED;
45
+ this.jti = jti;
46
+ }
47
+ }
48
+ exports.JwtRevokedError = JwtRevokedError;
49
+ /**
50
+ * One-time token has already been used (replay attack detected).
51
+ */
52
+ class JwtReplayError extends JwtError {
53
+ constructor(jti) {
54
+ super(`Token with JTI "${jti}" has already been used`);
55
+ this.code = types_1.JwtErrorCode.REPLAY;
56
+ this.jti = jti;
57
+ }
58
+ }
59
+ exports.JwtReplayError = JwtReplayError;
60
+ /**
61
+ * Token signature is invalid.
62
+ */
63
+ class JwtInvalidSignatureError extends JwtError {
64
+ constructor() {
65
+ super('Token signature is invalid');
66
+ this.code = types_1.JwtErrorCode.INVALID_SIGNATURE;
67
+ }
68
+ }
69
+ exports.JwtInvalidSignatureError = JwtInvalidSignatureError;
70
+ /**
71
+ * Token claims validation failed (missing or invalid aud, iss, etc).
72
+ */
73
+ class JwtInvalidClaimsError extends JwtError {
74
+ constructor(claim, reason) {
75
+ super(`Invalid claim "${claim}": ${reason}`);
76
+ this.code = types_1.JwtErrorCode.INVALID_CLAIMS;
77
+ this.claim = claim;
78
+ }
79
+ }
80
+ exports.JwtInvalidClaimsError = JwtInvalidClaimsError;
81
+ /**
82
+ * Token is malformed or cannot be decoded.
83
+ */
84
+ class JwtMalformedError extends JwtError {
85
+ constructor(reason) {
86
+ super(reason ? `Malformed token: ${reason}` : 'Token is malformed');
87
+ this.code = types_1.JwtErrorCode.MALFORMED;
88
+ }
89
+ }
90
+ exports.JwtMalformedError = JwtMalformedError;
91
+ /**
92
+ * Type guard to check if an error is a JwtError.
93
+ */
94
+ function isJwtError(error) {
95
+ return error instanceof JwtError;
96
+ }
97
+ /**
98
+ * Map of error codes to error classes for programmatic handling.
99
+ */
100
+ exports.JwtErrors = {
101
+ JwtExpiredError,
102
+ JwtRevokedError,
103
+ JwtReplayError,
104
+ JwtInvalidSignatureError,
105
+ JwtInvalidClaimsError,
106
+ JwtMalformedError,
107
+ };
108
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":";;;AAuGA,gCAEC;AAzGD,mCAAuC;AAEvC;;GAEG;AACH,MAAsB,QAAS,SAAQ,KAAK;IAGxC,YAAY,OAAe;QACvB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;QAClC,KAAK,CAAC,iBAAiB,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;IACpD,CAAC;IAED;;OAEG;IACH,MAAM;QACF,OAAO;YACH,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,IAAI,CAAC,IAAI;SAClB,CAAC;IACN,CAAC;CACJ;AAnBD,4BAmBC;AAED;;GAEG;AACH,MAAa,eAAgB,SAAQ,QAAQ;IAIzC,YAAY,SAAe;QACvB,KAAK,CAAC,oBAAoB,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;QAJhD,SAAI,GAAG,oBAAY,CAAC,OAAO,CAAC;QAKjC,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC/B,CAAC;CACJ;AARD,0CAQC;AAED;;GAEG;AACH,MAAa,eAAgB,SAAQ,QAAQ;IAIzC,YAAY,GAAW;QACnB,KAAK,CAAC,mBAAmB,GAAG,oBAAoB,CAAC,CAAC;QAJ7C,SAAI,GAAG,oBAAY,CAAC,OAAO,CAAC;QAKjC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACnB,CAAC;CACJ;AARD,0CAQC;AAED;;GAEG;AACH,MAAa,cAAe,SAAQ,QAAQ;IAIxC,YAAY,GAAW;QACnB,KAAK,CAAC,mBAAmB,GAAG,yBAAyB,CAAC,CAAC;QAJlD,SAAI,GAAG,oBAAY,CAAC,MAAM,CAAC;QAKhC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACnB,CAAC;CACJ;AARD,wCAQC;AAED;;GAEG;AACH,MAAa,wBAAyB,SAAQ,QAAQ;IAGlD;QACI,KAAK,CAAC,4BAA4B,CAAC,CAAC;QAH/B,SAAI,GAAG,oBAAY,CAAC,iBAAiB,CAAC;IAI/C,CAAC;CACJ;AAND,4DAMC;AAED;;GAEG;AACH,MAAa,qBAAsB,SAAQ,QAAQ;IAI/C,YAAY,KAAa,EAAE,MAAc;QACrC,KAAK,CAAC,kBAAkB,KAAK,MAAM,MAAM,EAAE,CAAC,CAAC;QAJxC,SAAI,GAAG,oBAAY,CAAC,cAAc,CAAC;QAKxC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACvB,CAAC;CACJ;AARD,sDAQC;AAED;;GAEG;AACH,MAAa,iBAAkB,SAAQ,QAAQ;IAG3C,YAAY,MAAe;QACvB,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,oBAAoB,MAAM,EAAE,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC;QAH/D,SAAI,GAAG,oBAAY,CAAC,SAAS,CAAC;IAIvC,CAAC;CACJ;AAND,8CAMC;AAED;;GAEG;AACH,SAAgB,UAAU,CAAC,KAAc;IACrC,OAAO,KAAK,YAAY,QAAQ,CAAC;AACrC,CAAC;AAED;;GAEG;AACU,QAAA,SAAS,GAAG;IACrB,eAAe;IACf,eAAe;IACf,cAAc;IACd,wBAAwB;IACxB,qBAAqB;IACrB,iBAAiB;CACX,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @bonapasogit-dev/jwt-manager
3
+ * High-performance JWT lifecycle management with JTI validation.
4
+ */
5
+ export { JwtManager, createJwtManager } from './jwtManager';
6
+ export { InMemoryTokenStore, createInMemoryTokenStore } from './tokenStore';
7
+ export type { Algorithm, JwtManagerConfig, JwtPayload, SignOptions, TokenStore, VerifyOptions, VerifyResult, } from './types';
8
+ export { JwtErrorCode } from './types';
9
+ export { JwtError, JwtExpiredError, JwtRevokedError, JwtReplayError, JwtInvalidSignatureError, JwtInvalidClaimsError, JwtMalformedError, JwtErrors, isJwtError, } from './errors';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAG5D,OAAO,EAAE,kBAAkB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAC;AAG5E,YAAY,EACR,SAAS,EACT,gBAAgB,EAChB,UAAU,EACV,WAAW,EACX,UAAU,EACV,aAAa,EACb,YAAY,GACf,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAGvC,OAAO,EACH,QAAQ,EACR,eAAe,EACf,eAAe,EACf,cAAc,EACd,wBAAwB,EACxB,qBAAqB,EACrB,iBAAiB,EACjB,SAAS,EACT,UAAU,GACb,MAAM,UAAU,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ /**
3
+ * @bonapasogit-dev/jwt-manager
4
+ * High-performance JWT lifecycle management with JTI validation.
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.isJwtError = exports.JwtErrors = exports.JwtMalformedError = exports.JwtInvalidClaimsError = exports.JwtInvalidSignatureError = exports.JwtReplayError = exports.JwtRevokedError = exports.JwtExpiredError = exports.JwtError = exports.JwtErrorCode = exports.createInMemoryTokenStore = exports.InMemoryTokenStore = exports.createJwtManager = exports.JwtManager = void 0;
8
+ // Core manager
9
+ var jwtManager_1 = require("./jwtManager");
10
+ Object.defineProperty(exports, "JwtManager", { enumerable: true, get: function () { return jwtManager_1.JwtManager; } });
11
+ Object.defineProperty(exports, "createJwtManager", { enumerable: true, get: function () { return jwtManager_1.createJwtManager; } });
12
+ // Token store implementations
13
+ var tokenStore_1 = require("./tokenStore");
14
+ Object.defineProperty(exports, "InMemoryTokenStore", { enumerable: true, get: function () { return tokenStore_1.InMemoryTokenStore; } });
15
+ Object.defineProperty(exports, "createInMemoryTokenStore", { enumerable: true, get: function () { return tokenStore_1.createInMemoryTokenStore; } });
16
+ var types_1 = require("./types");
17
+ Object.defineProperty(exports, "JwtErrorCode", { enumerable: true, get: function () { return types_1.JwtErrorCode; } });
18
+ // Errors
19
+ var errors_1 = require("./errors");
20
+ Object.defineProperty(exports, "JwtError", { enumerable: true, get: function () { return errors_1.JwtError; } });
21
+ Object.defineProperty(exports, "JwtExpiredError", { enumerable: true, get: function () { return errors_1.JwtExpiredError; } });
22
+ Object.defineProperty(exports, "JwtRevokedError", { enumerable: true, get: function () { return errors_1.JwtRevokedError; } });
23
+ Object.defineProperty(exports, "JwtReplayError", { enumerable: true, get: function () { return errors_1.JwtReplayError; } });
24
+ Object.defineProperty(exports, "JwtInvalidSignatureError", { enumerable: true, get: function () { return errors_1.JwtInvalidSignatureError; } });
25
+ Object.defineProperty(exports, "JwtInvalidClaimsError", { enumerable: true, get: function () { return errors_1.JwtInvalidClaimsError; } });
26
+ Object.defineProperty(exports, "JwtMalformedError", { enumerable: true, get: function () { return errors_1.JwtMalformedError; } });
27
+ Object.defineProperty(exports, "JwtErrors", { enumerable: true, get: function () { return errors_1.JwtErrors; } });
28
+ Object.defineProperty(exports, "isJwtError", { enumerable: true, get: function () { return errors_1.isJwtError; } });
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,eAAe;AACf,2CAA4D;AAAnD,wGAAA,UAAU,OAAA;AAAE,8GAAA,gBAAgB,OAAA;AAErC,8BAA8B;AAC9B,2CAA4E;AAAnE,gHAAA,kBAAkB,OAAA;AAAE,sHAAA,wBAAwB,OAAA;AAYrD,iCAAuC;AAA9B,qGAAA,YAAY,OAAA;AAErB,SAAS;AACT,mCAUkB;AATd,kGAAA,QAAQ,OAAA;AACR,yGAAA,eAAe,OAAA;AACf,yGAAA,eAAe,OAAA;AACf,wGAAA,cAAc,OAAA;AACd,kHAAA,wBAAwB,OAAA;AACxB,+GAAA,qBAAqB,OAAA;AACrB,2GAAA,iBAAiB,OAAA;AACjB,mGAAA,SAAS,OAAA;AACT,oGAAA,UAAU,OAAA"}
@@ -0,0 +1,78 @@
1
+ import type { JwtManagerConfig, JwtPayload, SignOptions, VerifyOptions, VerifyResult } from './types';
2
+ /**
3
+ * High-performance JWT manager with JTI validation.
4
+ * Implements secure token lifecycle with revocation support.
5
+ */
6
+ export declare class JwtManager {
7
+ private readonly algorithm;
8
+ private readonly secret?;
9
+ private readonly privateKey?;
10
+ private readonly publicKey?;
11
+ private readonly tokenStore;
12
+ private readonly defaultExpiresIn;
13
+ constructor(config: JwtManagerConfig);
14
+ /**
15
+ * Validate configuration on initialization.
16
+ */
17
+ private validateConfig;
18
+ /**
19
+ * Get the signing key based on algorithm type.
20
+ */
21
+ private getSigningKey;
22
+ /**
23
+ * Get the verification key based on algorithm type.
24
+ */
25
+ private getVerifyKey;
26
+ /**
27
+ * Sign a new JWT with auto-injected jti, iat, exp claims.
28
+ * All tokens include required security claims (jti, aud, iss, exp).
29
+ */
30
+ sign(options: SignOptions): string;
31
+ /**
32
+ * Verify a JWT's signature, expiry, and JTI status.
33
+ * Returns decoded payload if valid.
34
+ * @throws {JwtExpiredError} Token has expired
35
+ * @throws {JwtRevokedError} Token JTI is in denylist
36
+ * @throws {JwtReplayError} One-time token already used
37
+ * @throws {JwtInvalidSignatureError} Signature verification failed
38
+ * @throws {JwtInvalidClaimsError} Required claims missing/invalid
39
+ * @throws {JwtMalformedError} Token cannot be decoded
40
+ */
41
+ verify(token: string, options?: VerifyOptions): Promise<VerifyResult>;
42
+ /**
43
+ * Validate that required claims are present in the payload.
44
+ */
45
+ private validateRequiredClaims;
46
+ /**
47
+ * Revoke a token by adding its JTI to the denylist.
48
+ * Token will be rejected on future verification attempts.
49
+ * @param jti - The JWT ID to revoke
50
+ * @param expiresAt - When this revocation can be removed (should match token exp)
51
+ */
52
+ revoke(jti: string, expiresAt: number): Promise<void>;
53
+ /**
54
+ * Revoke a token by decoding it and extracting the JTI.
55
+ * @param token - The JWT string to revoke
56
+ */
57
+ revokeToken(token: string): Promise<void>;
58
+ /**
59
+ * Decode a JWT without verification.
60
+ * Use for inspection only, never trust the payload without verification.
61
+ */
62
+ decode(token: string): JwtPayload | null;
63
+ /**
64
+ * Check if a specific JTI has been revoked.
65
+ */
66
+ isRevoked(jti: string): Promise<boolean>;
67
+ /**
68
+ * Unrevoke a token by removing its JTI from the denylist.
69
+ * Use with caution - this re-enables a previously revoked token.
70
+ */
71
+ unrevoke(jti: string): Promise<void>;
72
+ }
73
+ /**
74
+ * Create a new JwtManager instance.
75
+ * Factory function for convenience.
76
+ */
77
+ export declare function createJwtManager(config: JwtManagerConfig): JwtManager;
78
+ //# sourceMappingURL=jwtManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwtManager.d.ts","sourceRoot":"","sources":["../src/jwtManager.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAER,gBAAgB,EAChB,UAAU,EACV,WAAW,EAEX,aAAa,EACb,YAAY,EACf,MAAM,SAAS,CAAC;AAcjB;;;GAGG;AACH,qBAAa,UAAU;IACnB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAS;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAa;IACxC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAS;gBAE9B,MAAM,EAAE,gBAAgB;IAWpC;;OAEG;IACH,OAAO,CAAC,cAAc;IAiBtB;;OAEG;IACH,OAAO,CAAC,aAAa;IAIrB;;OAEG;IACH,OAAO,CAAC,YAAY;IAIpB;;;OAGG;IACH,IAAI,CAAC,OAAO,EAAE,WAAW,GAAG,MAAM;IA0BlC;;;;;;;;;OASG;IACG,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,YAAY,CAAC;IA8D3E;;OAEG;IACH,OAAO,CAAC,sBAAsB;IAe9B;;;;;OAKG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3D;;;OAGG;IACG,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ/C;;;OAGG;IACH,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI;IASxC;;OAEG;IACG,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAI9C;;;OAGG;IACG,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAG7C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CAErE"}
@@ -0,0 +1,251 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.JwtManager = void 0;
37
+ exports.createJwtManager = createJwtManager;
38
+ const jsonwebtoken_1 = __importStar(require("jsonwebtoken"));
39
+ const ulid_1 = require("ulid");
40
+ const errors_1 = require("./errors");
41
+ const tokenStore_1 = require("./tokenStore");
42
+ /** One-time token marker in payload */
43
+ const ONE_TIME_TOKEN_KEY = '_ott';
44
+ /**
45
+ * High-performance JWT manager with JTI validation.
46
+ * Implements secure token lifecycle with revocation support.
47
+ */
48
+ class JwtManager {
49
+ constructor(config) {
50
+ this.algorithm = config.algorithm;
51
+ this.secret = config.secret;
52
+ this.privateKey = config.privateKey;
53
+ this.publicKey = config.publicKey;
54
+ this.tokenStore = config.tokenStore ?? new tokenStore_1.InMemoryTokenStore();
55
+ this.defaultExpiresIn = config.defaultExpiresIn ?? 3600;
56
+ this.validateConfig();
57
+ }
58
+ /**
59
+ * Validate configuration on initialization.
60
+ */
61
+ validateConfig() {
62
+ const isHmac = this.algorithm.startsWith('HS');
63
+ if (isHmac) {
64
+ if (!this.secret) {
65
+ throw new Error(`HMAC algorithm ${this.algorithm} requires a secret`);
66
+ }
67
+ }
68
+ else {
69
+ if (!this.privateKey) {
70
+ throw new Error(`Asymmetric algorithm ${this.algorithm} requires a privateKey`);
71
+ }
72
+ if (!this.publicKey) {
73
+ throw new Error(`Asymmetric algorithm ${this.algorithm} requires a publicKey`);
74
+ }
75
+ }
76
+ }
77
+ /**
78
+ * Get the signing key based on algorithm type.
79
+ */
80
+ getSigningKey() {
81
+ return this.algorithm.startsWith('HS') ? this.secret : this.privateKey;
82
+ }
83
+ /**
84
+ * Get the verification key based on algorithm type.
85
+ */
86
+ getVerifyKey() {
87
+ return this.algorithm.startsWith('HS') ? this.secret : this.publicKey;
88
+ }
89
+ /**
90
+ * Sign a new JWT with auto-injected jti, iat, exp claims.
91
+ * All tokens include required security claims (jti, aud, iss, exp).
92
+ */
93
+ sign(options) {
94
+ const now = Math.floor(Date.now() / 1000);
95
+ const expiresIn = options.expiresIn ?? this.defaultExpiresIn;
96
+ const payload = {
97
+ ...options.claims,
98
+ jti: (0, ulid_1.ulid)(),
99
+ aud: options.audience,
100
+ iss: options.issuer,
101
+ iat: now,
102
+ exp: now + expiresIn,
103
+ };
104
+ if (options.subject) {
105
+ payload.sub = options.subject;
106
+ }
107
+ if (options.oneTimeToken) {
108
+ payload[ONE_TIME_TOKEN_KEY] = true;
109
+ }
110
+ return jsonwebtoken_1.default.sign(payload, this.getSigningKey(), {
111
+ algorithm: this.algorithm,
112
+ });
113
+ }
114
+ /**
115
+ * Verify a JWT's signature, expiry, and JTI status.
116
+ * Returns decoded payload if valid.
117
+ * @throws {JwtExpiredError} Token has expired
118
+ * @throws {JwtRevokedError} Token JTI is in denylist
119
+ * @throws {JwtReplayError} One-time token already used
120
+ * @throws {JwtInvalidSignatureError} Signature verification failed
121
+ * @throws {JwtInvalidClaimsError} Required claims missing/invalid
122
+ * @throws {JwtMalformedError} Token cannot be decoded
123
+ */
124
+ async verify(token, options) {
125
+ let payload;
126
+ try {
127
+ const verifyOpts = {
128
+ algorithms: [this.algorithm],
129
+ clockTolerance: options?.clockTolerance ?? 0,
130
+ };
131
+ if (options?.audience !== undefined) {
132
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
133
+ verifyOpts.audience = options.audience;
134
+ }
135
+ if (options?.issuer !== undefined) {
136
+ verifyOpts.issuer = options.issuer;
137
+ }
138
+ payload = jsonwebtoken_1.default.verify(token, this.getVerifyKey(), verifyOpts);
139
+ }
140
+ catch (error) {
141
+ if (error instanceof jsonwebtoken_1.TokenExpiredError) {
142
+ throw new errors_1.JwtExpiredError(error.expiredAt);
143
+ }
144
+ if (error instanceof jsonwebtoken_1.JsonWebTokenError) {
145
+ if (error.message.includes('invalid signature')) {
146
+ throw new errors_1.JwtInvalidSignatureError();
147
+ }
148
+ if (error.message.includes('jwt malformed')) {
149
+ throw new errors_1.JwtMalformedError();
150
+ }
151
+ throw new errors_1.JwtMalformedError(error.message);
152
+ }
153
+ if (error instanceof jsonwebtoken_1.NotBeforeError) {
154
+ throw new errors_1.JwtInvalidClaimsError('nbf', 'Token not yet valid');
155
+ }
156
+ throw error;
157
+ }
158
+ // Validate required claims
159
+ this.validateRequiredClaims(payload);
160
+ // Check if JTI is revoked
161
+ const isRevoked = await this.tokenStore.has(payload.jti);
162
+ if (isRevoked) {
163
+ const isOneTimeToken = payload[ONE_TIME_TOKEN_KEY] === true;
164
+ if (isOneTimeToken) {
165
+ throw new errors_1.JwtReplayError(payload.jti);
166
+ }
167
+ throw new errors_1.JwtRevokedError(payload.jti);
168
+ }
169
+ // Handle one-time tokens - mark as used after first verification
170
+ const isOneTimeToken = payload[ONE_TIME_TOKEN_KEY] === true;
171
+ if (isOneTimeToken) {
172
+ await this.tokenStore.add(payload.jti, payload.exp);
173
+ }
174
+ return {
175
+ payload,
176
+ isOneTimeToken,
177
+ };
178
+ }
179
+ /**
180
+ * Validate that required claims are present in the payload.
181
+ */
182
+ validateRequiredClaims(payload) {
183
+ if (!payload.jti) {
184
+ throw new errors_1.JwtInvalidClaimsError('jti', 'Missing required claim');
185
+ }
186
+ if (!payload.aud) {
187
+ throw new errors_1.JwtInvalidClaimsError('aud', 'Missing required claim');
188
+ }
189
+ if (!payload.iss) {
190
+ throw new errors_1.JwtInvalidClaimsError('iss', 'Missing required claim');
191
+ }
192
+ if (typeof payload.exp !== 'number') {
193
+ throw new errors_1.JwtInvalidClaimsError('exp', 'Missing or invalid');
194
+ }
195
+ }
196
+ /**
197
+ * Revoke a token by adding its JTI to the denylist.
198
+ * Token will be rejected on future verification attempts.
199
+ * @param jti - The JWT ID to revoke
200
+ * @param expiresAt - When this revocation can be removed (should match token exp)
201
+ */
202
+ async revoke(jti, expiresAt) {
203
+ await this.tokenStore.add(jti, expiresAt);
204
+ }
205
+ /**
206
+ * Revoke a token by decoding it and extracting the JTI.
207
+ * @param token - The JWT string to revoke
208
+ */
209
+ async revokeToken(token) {
210
+ const payload = this.decode(token);
211
+ if (!payload || !payload.jti || typeof payload.exp !== 'number') {
212
+ throw new errors_1.JwtMalformedError('Cannot revoke token: invalid or missing claims');
213
+ }
214
+ await this.revoke(payload.jti, payload.exp);
215
+ }
216
+ /**
217
+ * Decode a JWT without verification.
218
+ * Use for inspection only, never trust the payload without verification.
219
+ */
220
+ decode(token) {
221
+ try {
222
+ const decoded = jsonwebtoken_1.default.decode(token, { json: true });
223
+ return decoded;
224
+ }
225
+ catch {
226
+ return null;
227
+ }
228
+ }
229
+ /**
230
+ * Check if a specific JTI has been revoked.
231
+ */
232
+ async isRevoked(jti) {
233
+ return this.tokenStore.has(jti);
234
+ }
235
+ /**
236
+ * Unrevoke a token by removing its JTI from the denylist.
237
+ * Use with caution - this re-enables a previously revoked token.
238
+ */
239
+ async unrevoke(jti) {
240
+ await this.tokenStore.remove(jti);
241
+ }
242
+ }
243
+ exports.JwtManager = JwtManager;
244
+ /**
245
+ * Create a new JwtManager instance.
246
+ * Factory function for convenience.
247
+ */
248
+ function createJwtManager(config) {
249
+ return new JwtManager(config);
250
+ }
251
+ //# sourceMappingURL=jwtManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwtManager.js","sourceRoot":"","sources":["../src/jwtManager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ import type { TokenStore } from './types';
2
+ /**
3
+ * In-memory implementation of TokenStore.
4
+ * Suitable for development and single-instance deployments.
5
+ * For production with multiple instances, use Redis or PostgreSQL.
6
+ */
7
+ export declare class InMemoryTokenStore implements TokenStore {
8
+ private readonly store;
9
+ private cleanupInterval;
10
+ /**
11
+ * Create a new InMemoryTokenStore.
12
+ * @param autoCleanupInterval - Interval in ms to auto-cleanup expired entries (default: 60000)
13
+ */
14
+ constructor(autoCleanupInterval?: number);
15
+ /**
16
+ * Add a JTI to the denylist with expiration time.
17
+ */
18
+ add(jti: string, expiresAt: number): Promise<void>;
19
+ /**
20
+ * Check if a JTI is in the denylist and not expired.
21
+ */
22
+ has(jti: string): Promise<boolean>;
23
+ /**
24
+ * Remove a JTI from the denylist.
25
+ */
26
+ remove(jti: string): Promise<void>;
27
+ /**
28
+ * Remove all expired entries from the store.
29
+ */
30
+ cleanup(): Promise<void>;
31
+ /**
32
+ * Get the current size of the denylist.
33
+ */
34
+ size(): number;
35
+ /**
36
+ * Clear all entries from the store.
37
+ */
38
+ clear(): void;
39
+ /**
40
+ * Stop the automatic cleanup interval.
41
+ */
42
+ destroy(): void;
43
+ /**
44
+ * Start automatic cleanup of expired entries.
45
+ */
46
+ private startAutoCleanup;
47
+ }
48
+ /**
49
+ * Create a new InMemoryTokenStore instance.
50
+ * Factory function for convenience.
51
+ */
52
+ export declare function createInMemoryTokenStore(autoCleanupInterval?: number): InMemoryTokenStore;
53
+ //# sourceMappingURL=tokenStore.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenStore.d.ts","sourceRoot":"","sources":["../src/tokenStore.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAE1C;;;;GAIG;AACH,qBAAa,kBAAmB,YAAW,UAAU;IACjD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAkC;IACxD,OAAO,CAAC,eAAe,CAA+C;IAEtE;;;OAGG;gBACS,mBAAmB,GAAE,MAAc;IAM/C;;OAEG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxD;;OAEG;IACG,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAgBxC;;OAEG;IACG,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIxC;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAS9B;;OAEG;IACH,IAAI,IAAI,MAAM;IAId;;OAEG;IACH,KAAK,IAAI,IAAI;IAIb;;OAEG;IACH,OAAO,IAAI,IAAI;IAOf;;OAEG;IACH,OAAO,CAAC,gBAAgB;CAY3B;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,mBAAmB,CAAC,EAAE,MAAM,GAAG,kBAAkB,CAEzF"}
@@ -0,0 +1,105 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InMemoryTokenStore = void 0;
4
+ exports.createInMemoryTokenStore = createInMemoryTokenStore;
5
+ /**
6
+ * In-memory implementation of TokenStore.
7
+ * Suitable for development and single-instance deployments.
8
+ * For production with multiple instances, use Redis or PostgreSQL.
9
+ */
10
+ class InMemoryTokenStore {
11
+ /**
12
+ * Create a new InMemoryTokenStore.
13
+ * @param autoCleanupInterval - Interval in ms to auto-cleanup expired entries (default: 60000)
14
+ */
15
+ constructor(autoCleanupInterval = 60000) {
16
+ this.store = new Map();
17
+ this.cleanupInterval = null;
18
+ if (autoCleanupInterval > 0) {
19
+ this.startAutoCleanup(autoCleanupInterval);
20
+ }
21
+ }
22
+ /**
23
+ * Add a JTI to the denylist with expiration time.
24
+ */
25
+ async add(jti, expiresAt) {
26
+ this.store.set(jti, expiresAt);
27
+ }
28
+ /**
29
+ * Check if a JTI is in the denylist and not expired.
30
+ */
31
+ async has(jti) {
32
+ const expiresAt = this.store.get(jti);
33
+ if (expiresAt === undefined) {
34
+ return false;
35
+ }
36
+ const now = Math.floor(Date.now() / 1000);
37
+ if (expiresAt < now) {
38
+ // Entry has expired, remove it
39
+ this.store.delete(jti);
40
+ return false;
41
+ }
42
+ return true;
43
+ }
44
+ /**
45
+ * Remove a JTI from the denylist.
46
+ */
47
+ async remove(jti) {
48
+ this.store.delete(jti);
49
+ }
50
+ /**
51
+ * Remove all expired entries from the store.
52
+ */
53
+ async cleanup() {
54
+ const now = Math.floor(Date.now() / 1000);
55
+ for (const [jti, expiresAt] of this.store.entries()) {
56
+ if (expiresAt < now) {
57
+ this.store.delete(jti);
58
+ }
59
+ }
60
+ }
61
+ /**
62
+ * Get the current size of the denylist.
63
+ */
64
+ size() {
65
+ return this.store.size;
66
+ }
67
+ /**
68
+ * Clear all entries from the store.
69
+ */
70
+ clear() {
71
+ this.store.clear();
72
+ }
73
+ /**
74
+ * Stop the automatic cleanup interval.
75
+ */
76
+ destroy() {
77
+ if (this.cleanupInterval) {
78
+ clearInterval(this.cleanupInterval);
79
+ this.cleanupInterval = null;
80
+ }
81
+ }
82
+ /**
83
+ * Start automatic cleanup of expired entries.
84
+ */
85
+ startAutoCleanup(intervalMs) {
86
+ this.cleanupInterval = setInterval(() => {
87
+ this.cleanup().catch(() => {
88
+ // Ignore cleanup errors in background task
89
+ });
90
+ }, intervalMs);
91
+ // Allow the process to exit even if cleanup is scheduled
92
+ if (this.cleanupInterval.unref) {
93
+ this.cleanupInterval.unref();
94
+ }
95
+ }
96
+ }
97
+ exports.InMemoryTokenStore = InMemoryTokenStore;
98
+ /**
99
+ * Create a new InMemoryTokenStore instance.
100
+ * Factory function for convenience.
101
+ */
102
+ function createInMemoryTokenStore(autoCleanupInterval) {
103
+ return new InMemoryTokenStore(autoCleanupInterval);
104
+ }
105
+ //# sourceMappingURL=tokenStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenStore.js","sourceRoot":"","sources":["../src/tokenStore.ts"],"names":[],"mappings":";;;AA+GA,4DAEC;AA/GD;;;;GAIG;AACH,MAAa,kBAAkB;IAI3B;;;OAGG;IACH,YAAY,sBAA8B,KAAK;QAP9B,UAAK,GAAwB,IAAI,GAAG,EAAE,CAAC;QAChD,oBAAe,GAA0C,IAAI,CAAC;QAOlE,IAAI,mBAAmB,GAAG,CAAC,EAAE,CAAC;YAC1B,IAAI,CAAC,gBAAgB,CAAC,mBAAmB,CAAC,CAAC;QAC/C,CAAC;IACL,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,SAAiB;QACpC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACnC,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,GAAG,CAAC,GAAW;QACjB,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACtC,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,KAAK,CAAC;QACjB,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC1C,IAAI,SAAS,GAAG,GAAG,EAAE,CAAC;YAClB,+BAA+B;YAC/B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvB,OAAO,KAAK,CAAC;QACjB,CAAC;QAED,OAAO,IAAI,CAAC;IAChB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,MAAM,CAAC,GAAW;QACpB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,OAAO;QACT,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC1C,KAAK,MAAM,CAAC,GAAG,EAAE,SAAS,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAClD,IAAI,SAAS,GAAG,GAAG,EAAE,CAAC;gBAClB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAC3B,CAAC;QACL,CAAC;IACL,CAAC;IAED;;OAEG;IACH,IAAI;QACA,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,KAAK;QACD,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,OAAO;QACH,IAAI,IAAI,CAAC,eAAe,EAAE,CAAC;YACvB,aAAa,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;YACpC,IAAI,CAAC,eAAe,GAAG,IAAI,CAAC;QAChC,CAAC;IACL,CAAC;IAED;;OAEG;IACK,gBAAgB,CAAC,UAAkB;QACvC,IAAI,CAAC,eAAe,GAAG,WAAW,CAAC,GAAG,EAAE;YACpC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE;gBACtB,2CAA2C;YAC/C,CAAC,CAAC,CAAC;QACP,CAAC,EAAE,UAAU,CAAC,CAAC;QAEf,yDAAyD;QACzD,IAAI,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;YAC7B,IAAI,CAAC,eAAe,CAAC,KAAK,EAAE,CAAC;QACjC,CAAC;IACL,CAAC;CACJ;AAlGD,gDAkGC;AAED;;;GAGG;AACH,SAAgB,wBAAwB,CAAC,mBAA4B;IACjE,OAAO,IAAI,kBAAkB,CAAC,mBAAmB,CAAC,CAAC;AACvD,CAAC"}
@@ -0,0 +1,120 @@
1
+ import type { JwtPayload as BaseJwtPayload } from 'jsonwebtoken';
2
+ /**
3
+ * Supported signing algorithms.
4
+ * RS256/ES256 preferred for shared environments.
5
+ */
6
+ export type Algorithm = 'HS256' | 'HS384' | 'HS512' | 'RS256' | 'RS384' | 'RS512' | 'ES256' | 'ES384' | 'ES512';
7
+ /**
8
+ * JWT payload with required security claims.
9
+ * All tokens MUST include jti, aud, iss, and exp.
10
+ */
11
+ export interface JwtPayload extends BaseJwtPayload {
12
+ /** JWT ID - unique identifier for this token (ULID) */
13
+ jti: string;
14
+ /** Audience - intended recipient(s) of the token */
15
+ aud: string | string[];
16
+ /** Issuer - who issued this token */
17
+ iss: string;
18
+ /** Expiration time (Unix timestamp) */
19
+ exp: number;
20
+ /** Issued at (Unix timestamp) */
21
+ iat: number;
22
+ /** Subject - typically the user ID */
23
+ sub?: string;
24
+ /** Custom claims */
25
+ [key: string]: unknown;
26
+ }
27
+ /**
28
+ * Options for signing a new token.
29
+ */
30
+ export interface SignOptions {
31
+ /** Token subject (e.g., user ID) */
32
+ subject?: string;
33
+ /** Token audience */
34
+ audience: string | string[];
35
+ /** Token issuer */
36
+ issuer: string;
37
+ /** Expiration time in seconds (default: 3600) */
38
+ expiresIn?: number;
39
+ /** Additional custom claims */
40
+ claims?: Record<string, unknown>;
41
+ /** Enable one-time token mode (JTI added to denylist after first use) */
42
+ oneTimeToken?: boolean;
43
+ }
44
+ /**
45
+ * Options for verifying a token.
46
+ */
47
+ export interface VerifyOptions {
48
+ /** Expected audience(s) */
49
+ audience?: string | string[];
50
+ /** Expected issuer */
51
+ issuer?: string;
52
+ /** Clock tolerance in seconds for exp/nbf checks */
53
+ clockTolerance?: number;
54
+ }
55
+ /**
56
+ * Result of a successful token verification.
57
+ */
58
+ export interface VerifyResult {
59
+ /** Decoded payload */
60
+ payload: JwtPayload;
61
+ /** Whether this is a one-time token */
62
+ isOneTimeToken: boolean;
63
+ }
64
+ /**
65
+ * Configuration for JwtManager.
66
+ */
67
+ export interface JwtManagerConfig {
68
+ /** Signing algorithm (default: RS256) */
69
+ algorithm: Algorithm;
70
+ /** Secret key for HMAC algorithms (HS256, HS384, HS512) */
71
+ secret?: string;
72
+ /** Private key for RSA/EC algorithms (RS256, RS384, RS512, ES256, etc.) */
73
+ privateKey?: string;
74
+ /** Public key for RSA/EC algorithms (RS256, RS384, RS512, ES256, etc.) */
75
+ publicKey?: string;
76
+ /** Token store for JTI denylist */
77
+ tokenStore?: TokenStore;
78
+ /** Default token expiration in seconds (default: 3600) */
79
+ defaultExpiresIn?: number;
80
+ }
81
+ /**
82
+ * Abstract interface for JTI storage (denylist/whitelist).
83
+ * Implementations can use Redis, PostgreSQL, or in-memory storage.
84
+ */
85
+ export interface TokenStore {
86
+ /**
87
+ * Add a JTI to the denylist.
88
+ * @param jti - The JWT ID to blacklist
89
+ * @param expiresAt - Unix timestamp when this entry can be removed
90
+ */
91
+ add(jti: string, expiresAt: number): Promise<void>;
92
+ /**
93
+ * Check if a JTI is in the denylist.
94
+ * @param jti - The JWT ID to check
95
+ * @returns true if JTI is blacklisted
96
+ */
97
+ has(jti: string): Promise<boolean>;
98
+ /**
99
+ * Remove a JTI from the denylist.
100
+ * @param jti - The JWT ID to remove
101
+ */
102
+ remove(jti: string): Promise<void>;
103
+ /**
104
+ * Clean up expired entries from the store.
105
+ * Should be called periodically.
106
+ */
107
+ cleanup(): Promise<void>;
108
+ }
109
+ /**
110
+ * Error codes for JWT operations.
111
+ */
112
+ export declare enum JwtErrorCode {
113
+ EXPIRED = "ERR_JWT_EXPIRED",
114
+ REVOKED = "ERR_JWT_REVOKED",
115
+ REPLAY = "ERR_JWT_REPLAY",
116
+ INVALID_SIGNATURE = "ERR_JWT_INVALID_SIGNATURE",
117
+ INVALID_CLAIMS = "ERR_JWT_INVALID_CLAIMS",
118
+ MALFORMED = "ERR_JWT_MALFORMED"
119
+ }
120
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,cAAc,CAAC;AAEjE;;;GAGG;AACH,MAAM,MAAM,SAAS,GACf,OAAO,GACP,OAAO,GACP,OAAO,GACP,OAAO,GACP,OAAO,GACP,OAAO,GACP,OAAO,GACP,OAAO,GACP,OAAO,CAAC;AAEd;;;GAGG;AACH,MAAM,WAAW,UAAW,SAAQ,cAAc;IAC9C,uDAAuD;IACvD,GAAG,EAAE,MAAM,CAAC;IACZ,oDAAoD;IACpD,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACvB,qCAAqC;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,uCAAuC;IACvC,GAAG,EAAE,MAAM,CAAC;IACZ,iCAAiC;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,sCAAsC;IACtC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oBAAoB;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IACxB,oCAAoC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,qBAAqB;IACrB,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC5B,mBAAmB;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+BAA+B;IAC/B,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,yEAAyE;IACzE,YAAY,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,2BAA2B;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAC7B,sBAAsB;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,cAAc,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IACzB,sBAAsB;IACtB,OAAO,EAAE,UAAU,CAAC;IACpB,uCAAuC;IACvC,cAAc,EAAE,OAAO,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC7B,yCAAyC;IACzC,SAAS,EAAE,SAAS,CAAC;IACrB,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,0DAA0D;IAC1D,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED;;;GAGG;AACH,MAAM,WAAW,UAAU;IACvB;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnD;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAEnC;;;OAGG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnC;;;OAGG;IACH,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED;;GAEG;AACH,oBAAY,YAAY;IACpB,OAAO,oBAAoB;IAC3B,OAAO,oBAAoB;IAC3B,MAAM,mBAAmB;IACzB,iBAAiB,8BAA8B;IAC/C,cAAc,2BAA2B;IACzC,SAAS,sBAAsB;CAClC"}
package/dist/types.js ADDED
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JwtErrorCode = void 0;
4
+ /**
5
+ * Error codes for JWT operations.
6
+ */
7
+ var JwtErrorCode;
8
+ (function (JwtErrorCode) {
9
+ JwtErrorCode["EXPIRED"] = "ERR_JWT_EXPIRED";
10
+ JwtErrorCode["REVOKED"] = "ERR_JWT_REVOKED";
11
+ JwtErrorCode["REPLAY"] = "ERR_JWT_REPLAY";
12
+ JwtErrorCode["INVALID_SIGNATURE"] = "ERR_JWT_INVALID_SIGNATURE";
13
+ JwtErrorCode["INVALID_CLAIMS"] = "ERR_JWT_INVALID_CLAIMS";
14
+ JwtErrorCode["MALFORMED"] = "ERR_JWT_MALFORMED";
15
+ })(JwtErrorCode || (exports.JwtErrorCode = JwtErrorCode = {}));
16
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":";;;AAgIA;;GAEG;AACH,IAAY,YAOX;AAPD,WAAY,YAAY;IACpB,2CAA2B,CAAA;IAC3B,2CAA2B,CAAA;IAC3B,yCAAyB,CAAA;IACzB,+DAA+C,CAAA;IAC/C,yDAAyC,CAAA;IACzC,+CAA+B,CAAA;AACnC,CAAC,EAPW,YAAY,4BAAZ,YAAY,QAOvB"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@bonapasogit-dev/jwt-manager",
3
+ "version": "1.0.0",
4
+ "description": "High-performance JWT lifecycle management with JTI validation",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/bonapasogit-dev/bonatools.git"
10
+ },
11
+ "files": [
12
+ "dist"
13
+ ],
14
+ "scripts": {
15
+ "build": "npx tsc",
16
+ "test": "vitest run",
17
+ "test:watch": "vitest",
18
+ "prepublishOnly": "npm run build"
19
+ },
20
+ "keywords": [
21
+ "jwt",
22
+ "jti",
23
+ "token",
24
+ "authentication",
25
+ "security"
26
+ ],
27
+ "author": "",
28
+ "license": "MIT",
29
+ "dependencies": {
30
+ "jsonwebtoken": "^9.0.2",
31
+ "ulid": "^2.3.0"
32
+ },
33
+ "devDependencies": {
34
+ "@types/jsonwebtoken": "^9.0.6",
35
+ "@types/node": "^20.11.0",
36
+ "typescript": "^5.3.3",
37
+ "vitest": "^1.2.0"
38
+ },
39
+ "engines": {
40
+ "node": ">=18.0.0"
41
+ }
42
+ }