@sourceregistry/node-jwt 1.0.0 → 1.2.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 CHANGED
@@ -1,96 +1,135 @@
1
- # 🔐 node-jwt
2
-
1
+ # 🔐 @sourceregistry/node-jwt
3
2
  [![npm version](https://img.shields.io/npm/v/@sourceregistry/node-jwt?logo=npm)](https://www.npmjs.com/package/@sourceregistry/node-jwt)
4
- [![License](https://img.shields.io/npm/l/@sourceregistry/node-jwt)](LICENSE)
5
- [![Tests](https://github.com/SourceRegistry/node-jwt/actions/workflows/test.yml/badge.svg)](https://github.com/SourceRegistry/node-jwt/actions)
6
- [![Coverage](https://img.shields.io/codecov/c/github/SourceRegistry/node-jwt)](https://codecov.io/gh/SourceRegistry/node-jwt)
7
-
8
- A **minimal**, **secure**, and **production-ready** JWT (JSON Web Token) library for Node.js with **zero dependencies**. Supports all standard signing algorithms (HMAC, RSA, ECDSA) and full claim validation.
3
+ [![License](https://img.shields.io/npm/l/@sourceregistry/node-jwt)](https://github.com/SourceRegistry/node-jwt/blob/main/LICENSE)
4
+ [![CI](https://github.com/SourceRegistry/node-jwt/actions/workflows/test.yml/badge.svg)](https://github.com/SourceRegistry/node-jwt/actions)
5
+ [![Codecov](https://img.shields.io/codecov/c/github/SourceRegistry/node-jwt)](https://codecov.io/gh/SourceRegistry/node-jwt)
9
6
 
10
- > **Why another JWT library?**
11
- > Most JWT libraries are bloated, have security pitfalls, or lack proper TypeScript support. This library is:
12
- > - **Tiny**
13
- > - **Secure by default** (correct ECDSA/RSA encoding, time validation)
14
- > - **TypeScript-first** with full JSDoc
15
- > - **No external dependencies**
16
- > - **100% test coverage**
7
+ A minimal, secure, and production-ready JWT (JSON Web Token) library for Node.js with zero dependencies. Supports all standard signing algorithms (HMAC, RSA, ECDSA, EdDSA, RSASSA-PSS) and full claim validation.
17
8
 
18
- ---
9
+ ✨ **Why another JWT library?**
10
+ Most JWT libraries are bloated, have security pitfalls, or lack proper TypeScript support. This library is:
19
11
 
20
- ## 📦 Installation
12
+ - **Tiny**
13
+ - **Secure by default** (correct ECDSA/RSA/PSS/EdDSA encoding, time validation, algorithm whitelisting)
14
+ - **TypeScript-first** with full JSDoc
15
+ - **No external dependencies**
16
+ - **100% test coverage**
17
+ - **Dual API**: Sync and Promise-based
21
18
 
19
+ 📦 **Installation**
22
20
  ```bash
23
21
  npm install @sourceregistry/node-jwt
24
22
  ```
25
-
26
- > **Requires Node.js ≥ 16**
23
+ Requires Node.js ≥ 16
27
24
 
28
25
  ---
29
26
 
30
- ## 🚀 Quick Start
27
+ 🚀 **Quick Start**
31
28
 
32
- ### Sign a token
29
+ ### Sync API (default)
33
30
  ```ts
34
- import { sign } from '@sourceregistry/node-jwt';
31
+ import { sign, verify, decode } from '@sourceregistry/node-jwt';
35
32
 
33
+ // Sign
36
34
  const token = sign(
37
35
  { sub: '1234567890', name: 'John Doe', iat: Math.floor(Date.now() / 1000) },
38
36
  'your-secret-key',
39
37
  { alg: 'HS256' }
40
38
  );
41
- ```
42
-
43
- ### Verify a token
44
- ```ts
45
- import { verify } from '@sourceregistry/node-jwt';
46
-
47
- const result = verify(token, 'your-secret-key');
48
39
 
40
+ // Verify
41
+ const result = verify(token, 'your-secret-key', { issuer: 'https://example.com' });
49
42
  if (result.valid) {
50
43
  console.log('Payload:', result.payload);
51
44
  } else {
52
45
  console.error('JWT Error:', result.error.code, result.error.reason);
53
46
  }
47
+
48
+ // Decode (unsafe)
49
+ const { header, payload, signature } = decode(token);
54
50
  ```
55
51
 
56
- ### Decode (unsafe — no verification)
52
+ ### Promise API (`/promises`)
57
53
  ```ts
58
- import { decode } from '@sourceregistry/node-jwt';
54
+ import { sign, verify, decode } from '@sourceregistry/node-jwt/promises';
59
55
 
60
- const { header, payload, signature } = decode(token);
56
+ // Sign
57
+ const token = await sign(
58
+ { sub: '1234567890', name: 'John Doe', iat: Math.floor(Date.now() / 1000) },
59
+ 'your-secret-key',
60
+ { alg: 'HS256' }
61
+ );
62
+
63
+ // Verify
64
+ try {
65
+ const { payload, header, signature } = await verify(token, 'your-secret-key', {
66
+ issuer: 'https://example.com',
67
+ audience: 'my-app',
68
+ algorithms: ['HS256']
69
+ });
70
+ console.log('Payload:', payload);
71
+ } catch (error) {
72
+ console.error('JWT Error:', error.code, error.reason);
73
+ }
74
+
75
+ // Decode (unsafe)
76
+ const { header, payload, signature } = await decode(token);
61
77
  ```
62
78
 
63
79
  ---
64
80
 
65
- ## 🔑 Supported Algorithms
81
+ 🔑 **Supported Algorithms**
82
+
83
+ | Algorithm | Type | Secret Type |
84
+ |-------------|--------------|------------------------------------------|
85
+ | HS256 | HMAC | `string \| Buffer` |
86
+ | HS384 | HMAC | `string \| Buffer` |
87
+ | HS512 | HMAC | `string \| Buffer` |
88
+ | RS256 | RSA | Private key (sign), Public key (verify) |
89
+ | RS384 | RSA | Private key (sign), Public key (verify) |
90
+ | RS512 | RSA | Private key (sign), Public key (verify) |
91
+ | PS256 | RSA-PSS | Private key (sign), Public key (verify) |
92
+ | PS384 | RSA-PSS | Private key (sign), Public key (verify) |
93
+ | PS512 | RSA-PSS | Private key (sign), Public key (verify) |
94
+ | ES256 | ECDSA | Private key (sign), Public key (verify) |
95
+ | ES384 | ECDSA | Private key (sign), Public key (verify) |
96
+ | ES512 | ECDSA | Private key (sign), Public key (verify) |
97
+ | ES256K | ECDSA (secp256k1) | Private key (sign), Public key (verify) |
98
+ | EdDSA | Ed25519 | Private key (sign), Public key (verify) |
99
+
100
+ > 💡 Keys must be in PEM format or as Node.js `KeyObject` (e.g., from `crypto.generateKeyPairSync`).
66
101
 
67
- | Algorithm | Type | Secret Type |
68
- |-----------|---------|---------------------------------|
69
- | `HS256` | HMAC | `string \| Buffer` |
70
- | `HS384` | HMAC | `string \| Buffer` |
71
- | `HS512` | HMAC | `string \| Buffer` |
72
- | `RS256` | RSA | Private key (signing)<br>Public key (verifying) |
73
- | `RS384` | RSA | Private key (signing)<br>Public key (verifying) |
74
- | `RS512` | RSA | Private key (signing)<br>Public key (verifying) |
75
- | `ES256` | ECDSA | Private key (signing)<br>Public key (verifying) |
76
- | `ES384` | ECDSA | Private key (signing)<br>Public key (verifying) |
77
- | `ES512` | ECDSA | Private key (signing)<br>Public key (verifying) |
102
+ ---
78
103
 
79
- > 💡 **Note**: RSA/ECDSA keys must be in **PEM format** or as Node.js `KeyObject`.
104
+ 🛡️ **Security Features**
105
+
106
+ ✅ Correct ECDSA signatures (DER-encoded, not IEEE P1363)
107
+ ✅ Full RSASSA-PSS and Ed25519 support
108
+ ✅ Strict algorithm validation with **whitelist** (`algorithms` option) to prevent algorithm confusion
109
+ ✅ Time claim validation (`exp`, `nbf`, `iat`) with **clock skew** tolerance
110
+ ✅ Optional validation for:
111
+  • Issuer (`iss`)
112
+  • Subject (`sub`)
113
+  • Audience (`aud`)
114
+  • JWT ID (`jti`)
115
+ ✅ Maximum token age enforcement (`maxTokenAge`)
116
+ ✅ Type header enforcement (`typ: 'JWT'`)
117
+ ✅ Timing-safe signature comparison
118
+ ✅ No unsafe defaults
80
119
 
81
120
  ---
82
121
 
83
- ## 🛡️ Security Features
122
+ 📚 **API Reference**
84
123
 
85
- - **Correct ECDSA signatures** (DER-encoded, not IEEE P1363)
86
- - ✅ **Strict algorithm validation** (prevents algorithm confusion attacks)
87
- - ✅ **Time claim validation** (`exp`, `nbf`, `iat`) with **clock skew tolerance**
88
- - ✅ **Type header enforcement** (`typ: 'JWT'`)
89
- - ✅ **No unsafe defaults**
124
+ ### Sync vs Promise API
90
125
 
91
- ---
126
+ | Operation | Sync Return | Promise Behavior |
127
+ |----------|-------------|------------------|
128
+ | `sign()` | `string` | Resolves to `string` |
129
+ | `decode()` | `{ header, payload, signature }` | Resolves to same object |
130
+ | `verify()` | `{ valid: true, ... } \| { valid: false, error }` | **Resolves** on success<br>**Rejects** with `{ reason, code }` on failure |
92
131
 
93
- ## 📚 API Reference
132
+ ---
94
133
 
95
134
  ### `sign(payload, secret, options?)`
96
135
  Sign a JWT.
@@ -112,60 +151,99 @@ Verify and validate a JWT.
112
151
  - `token`: JWT string
113
152
  - `secret`: Key for verification
114
153
  - `options`:
154
+ - `algorithms`: Array of allowed algorithms (e.g., `['HS256', 'RS256']`)
155
+ - `issuer`: Required value for the `iss` claim
156
+ - `subject`: Required value for the `sub` claim
157
+ - `audience`: Required value(s) for the `aud` claim (`string` or `string[]`)
158
+ - `jwtId`: Required value for the `jti` claim
115
159
  - `ignoreExpiration`: Skip `exp` check (default: `false`)
116
160
  - `clockSkew`: Tolerance in seconds for time validation (default: `0`)
161
+ - `maxTokenAge`: Maximum allowed token age in seconds (from `iat`)
117
162
 
118
- Returns:
163
+ #### Sync Usage:
119
164
  ```ts
120
- | { valid: true; header: JWTHeader; payload: JWTPayload; signature: string }
121
- | { valid: false; error: { reason: string; code: string } }
165
+ const result = verify(token, secret, { issuer: 'https://example.com' });
166
+ if (result.valid) {
167
+ // success
168
+ } else {
169
+ // handle error: result.error
170
+ }
171
+ ```
172
+
173
+ #### Promise Usage:
174
+ ```ts
175
+ try {
176
+ const { header, payload, signature } = await verify(token, secret, { issuer: 'https://example.com' });
177
+ // success
178
+ } catch (error) {
179
+ // handle error: error.reason, error.code
180
+ }
122
181
  ```
123
182
 
124
- **Error Codes**:
183
+ #### Error Codes:
125
184
  - `INVALID_TOKEN`: Malformed token structure
126
185
  - `INVALID_ALGORITHM`: Unsupported algorithm
186
+ - `ALGORITHM_NOT_ALLOWED`: Algorithm not in allowed list
127
187
  - `INVALID_TYPE`: Invalid `typ` header
128
188
  - `INVALID_SIGNATURE`: Signature mismatch
129
189
  - `TOKEN_EXPIRED`: `exp` claim exceeded
130
190
  - `TOKEN_NOT_ACTIVE`: `nbf` claim not reached
131
191
  - `TOKEN_FUTURE_ISSUED`: `iat` claim in future
192
+ - `TOKEN_TOO_OLD`: Token age exceeds `maxTokenAge`
193
+ - `MISSING_ISSUER` / `INVALID_ISSUER`
194
+ - `MISSING_SUBJECT` / `INVALID_SUBJECT`
195
+ - `MISSING_AUDIENCE` / `INVALID_AUDIENCE`
196
+ - `MISSING_JTI` / `INVALID_JTI`
132
197
 
133
198
  ---
134
199
 
135
200
  ### `decode(token)`
136
- Decode a JWT without verification (use with caution!).
201
+ Decode a JWT without verification (**use with caution!**).
137
202
 
138
203
  - `token`: JWT string
139
-
140
- Returns: `{ header, payload, signature }`
141
-
142
- Throws on malformed tokens.
204
+ - Returns: `{ header, payload, signature }`
205
+ - Throws on malformed tokens (sync) / Rejects (promise)
143
206
 
144
207
  ---
145
208
 
146
- ## 🧪 Testing
147
-
148
- This library has **100% test coverage** with Vitest:
149
-
209
+ 🧪 **Testing**
210
+ This library has 100% test coverage with Vitest:
150
211
  ```bash
151
212
  npm test
152
213
  npm run test:coverage
153
214
  ```
154
215
 
155
216
  Tests include:
156
- - All algorithms (HMAC, RSA, ECDSA)
157
- - Time validation edge cases
217
+ - All algorithms (HMAC, RSA, ECDSA, EdDSA, PSS)
218
+ - Time validation (`exp`, `nbf`, `iat`, `clockSkew`, `maxTokenAge`)
219
+ - Claim validation (`iss`, `sub`, `aud`, `jti`)
220
+ - Algorithm whitelisting
158
221
  - Malformed token handling
159
- - Signature verification
222
+ - Signature verification (including timing-safe comparison)
160
223
  - Custom claims
224
+ - Both sync and promise APIs
161
225
 
162
226
  ---
163
227
 
164
- ## 🙌 Contributing
228
+ 📦 **Exports**
229
+ This package provides two entrypoints:
230
+
231
+ | Import | Description |
232
+ |--------|-------------|
233
+ | `@sourceregistry/node-jwt` | Sync API (default) |
234
+ | `@sourceregistry/node-jwt/promises` | Promise-based API |
165
235
 
236
+ Both include full TypeScript types and JSDoc.
237
+
238
+ ---
239
+
240
+ 🙌 **Contributing**
166
241
  PRs welcome! Please:
167
- 1. Add tests for new features
168
- 2. Maintain 100% coverage
169
- 3. Follow existing code style
242
+ - Add tests for new features
243
+ - Maintain 100% coverage
244
+ - Follow existing code style
170
245
 
171
246
  Found a security issue? [Report it responsibly](mailto:a.p.a.slaa@projectsource.nl).
247
+
248
+ 🔗 **GitHub**: [github.com/SourceRegistry/node-jwt](https://github.com/SourceRegistry/node-jwt)
249
+ 📦 **npm**: [@sourceregistry/node-jwt](https://www.npmjs.com/package/@sourceregistry/node-jwt)
package/dist/index.cjs.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("crypto"),d={encode:e=>Buffer.from(e).toString("base64url"),decode:e=>Buffer.from(e,"base64url").toString()},c={HS256:{sign:(e,r)=>a.createHmac("sha256",r).update(e).digest("base64url"),verify:(e,r,t)=>a.createHmac("sha256",r).update(e).digest("base64url")===t},HS384:{sign:(e,r)=>a.createHmac("sha384",r).update(e).digest("base64url"),verify:(e,r,t)=>a.createHmac("sha384",r).update(e).digest("base64url")===t},HS512:{sign:(e,r)=>a.createHmac("sha512",r).update(e).digest("base64url"),verify:(e,r,t)=>a.createHmac("sha512",r).update(e).digest("base64url")===t},RS256:{sign:(e,r)=>a.createSign("RSA-SHA256").update(e).end().sign(r).toString("base64url"),verify:(e,r,t)=>a.createVerify("RSA-SHA256").update(e).end().verify(r,Buffer.from(t,"base64url"))},RS384:{sign:(e,r)=>a.createSign("RSA-SHA384").update(e).end().sign(r).toString("base64url"),verify:(e,r,t)=>a.createVerify("RSA-SHA384").update(e).end().verify(r,Buffer.from(t,"base64url"))},RS512:{sign:(e,r)=>a.createSign("RSA-SHA512").update(e).end().sign(r).toString("base64url"),verify:(e,r,t)=>a.createVerify("RSA-SHA512").update(e).end().verify(r,Buffer.from(t,"base64url"))},ES256:{sign:(e,r)=>a.createSign("SHA256").update(e).end().sign(r).toString("base64url"),verify:(e,r,t)=>a.createVerify("SHA256").update(e).end().verify(r,Buffer.from(t,"base64url"))},ES384:{sign:(e,r)=>a.createSign("SHA384").update(e).end().sign(r).toString("base64url"),verify:(e,r,t)=>a.createVerify("SHA384").update(e).end().verify(r,Buffer.from(t,"base64url"))},ES512:{sign:(e,r)=>a.createSign("SHA512").update(e).end().sign(r).toString("base64url"),verify:(e,r,t)=>a.createVerify("SHA512").update(e).end().verify(r,Buffer.from(t,"base64url"))}},b=Object.keys(c),S=e=>{const r=e.split(".");if(r.length!==3)throw new Error('Invalid JWT: must contain exactly 3 parts separated by "."');const[t,s,i]=r;if(!t||!s||!i)throw new Error("Invalid JWT: empty part detected");try{const n=JSON.parse(d.decode(t)),o=JSON.parse(d.decode(s));return{header:n,payload:o,signature:i}}catch(n){throw new Error(`Invalid JWT: malformed header or payload (${n.message})`)}},y=(e,r,t={})=>{const s=t.alg??"HS256",i=t.typ??"JWT";if(!(s in c))throw new Error(`Unsupported algorithm: ${s}`);const n={alg:s,typ:i};t.kid&&(n.kid=t.kid);const o=d.encode(JSON.stringify(n)),u=d.encode(JSON.stringify(e)),f=`${o}.${u}`,p=c[s].sign(f,r);return`${o}.${u}.${p}`},v=(e,r,t={})=>{let s;try{s=S(e)}catch(A){return{valid:!1,error:{reason:A.message,code:"INVALID_TOKEN"}}}const{header:i,payload:n,signature:o}=s,u=i.alg;if(!(u in c))return{valid:!1,error:{reason:`Unsupported or unknown algorithm: ${i.alg}`,code:"INVALID_ALGORITHM"}};if(i.typ&&i.typ!=="JWT")return{valid:!1,error:{reason:`Invalid token type: expected 'JWT', got '${i.typ}'`,code:"INVALID_TYPE"}};const f=`${d.encode(JSON.stringify(i))}.${d.encode(JSON.stringify(n))}`;if(!c[u].verify(f,r,o))return{valid:!1,error:{reason:"Signature verification failed",code:"INVALID_SIGNATURE"}};const g=Math.floor(Date.now()/1e3),l=t.clockSkew??0;return!t.ignoreExpiration&&n.exp!==void 0&&g>n.exp+l?{valid:!1,error:{reason:"Token expired",code:"TOKEN_EXPIRED"}}:n.nbf!==void 0&&g+l<n.nbf?{valid:!1,error:{reason:"Token not yet valid",code:"TOKEN_NOT_ACTIVE"}}:n.iat!==void 0&&g+l<n.iat?{valid:!1,error:{reason:"Token issued in the future",code:"TOKEN_FUTURE_ISSUED"}}:{valid:!0,header:i,payload:n,signature:o}},h={sign:y,verify:v,decode:S,algorithms:c};exports.JWT=h;exports.SignatureAlgorithm=c;exports.SupportedAlgorithms=b;exports.base64Url=d;exports.decode=S;exports.sign=y;exports.verify=v;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const a=require("crypto"),c={encode:e=>Buffer.from(e).toString("base64url"),decode:e=>Buffer.from(e,"base64url").toString()},y=(e,r)=>e.length!==r.length?!1:a.timingSafeEqual(Buffer.from(e),Buffer.from(r)),f={HS256:{sign:(e,r)=>a.createHmac("sha256",r).update(e).digest("base64url"),verify:(e,r,t)=>{const i=a.createHmac("sha256",r).update(e).digest("base64url");return y(i,t)}},HS384:{sign:(e,r)=>a.createHmac("sha384",r).update(e).digest("base64url"),verify:(e,r,t)=>{const i=a.createHmac("sha384",r).update(e).digest("base64url");return y(i,t)}},HS512:{sign:(e,r)=>a.createHmac("sha512",r).update(e).digest("base64url"),verify:(e,r,t)=>{const i=a.createHmac("sha512",r).update(e).digest("base64url");return y(i,t)}},RS256:{sign:(e,r)=>a.createSign("RSA-SHA256").update(e).end().sign(r).toString("base64url"),verify:(e,r,t)=>{try{return a.createVerify("RSA-SHA256").update(e).end().verify(r,Buffer.from(t,"base64url"))}catch{return!1}}},RS384:{sign:(e,r)=>a.createSign("RSA-SHA384").update(e).end().sign(r).toString("base64url"),verify:(e,r,t)=>{try{return a.createVerify("RSA-SHA384").update(e).end().verify(r,Buffer.from(t,"base64url"))}catch{return!1}}},RS512:{sign:(e,r)=>a.createSign("RSA-SHA512").update(e).end().sign(r).toString("base64url"),verify:(e,r,t)=>{try{return a.createVerify("RSA-SHA512").update(e).end().verify(r,Buffer.from(t,"base64url"))}catch{return!1}}},ES256:{sign:(e,r)=>a.createSign("SHA256").update(e).end().sign(r).toString("base64url"),verify:(e,r,t)=>{try{return a.createVerify("SHA256").update(e).end().verify(r,Buffer.from(t,"base64url"))}catch{return!1}}},ES384:{sign:(e,r)=>a.createSign("SHA384").update(e).end().sign(r).toString("base64url"),verify:(e,r,t)=>{try{return a.createVerify("SHA384").update(e).end().verify(r,Buffer.from(t,"base64url"))}catch{return!1}}},ES512:{sign:(e,r)=>a.createSign("SHA512").update(e).end().sign(r).toString("base64url"),verify:(e,r,t)=>{try{return a.createVerify("SHA512").update(e).end().verify(r,Buffer.from(t,"base64url"))}catch{return!1}}},ES256K:{sign:(e,r)=>a.createSign("SHA256").update(e).end().sign(r).toString("base64url"),verify:(e,r,t)=>{try{return a.createVerify("SHA256").update(e).end().verify(r,Buffer.from(t,"base64url"))}catch{return!1}}},PS256:{sign:(e,r)=>a.createSign("RSA-SHA256").update(e).end().sign({key:r,padding:a.constants.RSA_PKCS1_PSS_PADDING,saltLength:32}).toString("base64url"),verify:(e,r,t)=>{try{return a.createVerify("RSA-SHA256").update(e).end().verify({key:r,padding:a.constants.RSA_PKCS1_PSS_PADDING,saltLength:32},Buffer.from(t,"base64url"))}catch{return!1}}},PS384:{sign:(e,r)=>a.createSign("RSA-SHA384").update(e).end().sign({key:r,padding:a.constants.RSA_PKCS1_PSS_PADDING,saltLength:48}).toString("base64url"),verify:(e,r,t)=>{try{return a.createVerify("RSA-SHA384").update(e).end().verify({key:r,padding:a.constants.RSA_PKCS1_PSS_PADDING,saltLength:48},Buffer.from(t,"base64url"))}catch{return!1}}},PS512:{sign:(e,r)=>a.createSign("RSA-SHA512").update(e).end().sign({key:r,padding:a.constants.RSA_PKCS1_PSS_PADDING,saltLength:64}).toString("base64url"),verify:(e,r,t)=>{try{return a.createVerify("RSA-SHA512").update(e).end().verify({key:r,padding:a.constants.RSA_PKCS1_PSS_PADDING,saltLength:64},Buffer.from(t,"base64url"))}catch{return!1}}},EdDSA:{sign:(e,r)=>a.sign(null,typeof e=="string"?Buffer.from(e,"utf8"):e,r).toString("base64url"),verify:(e,r,t)=>{try{return a.verify(null,typeof e=="string"?Buffer.from(e,"utf8"):e,r,Buffer.from(t,"base64url"))}catch{return!1}}}},T=Object.keys(f),A=e=>{const r=e.split(".");if(r.length!==3)throw new Error('Invalid JWT: must contain exactly 3 parts separated by "."');const[t,i,s]=r;if(!t||!i||!s)throw new Error("Invalid JWT: empty part detected");try{const n=JSON.parse(c.decode(t)),u=JSON.parse(c.decode(i));return{header:n,payload:u,signature:s}}catch(n){throw new Error(`Invalid JWT: malformed header or payload (${n.message})`)}},m=(e,r,t={})=>{const i=t.alg??"HS256",s=t.typ??"JWT";if(!(i in f))throw new Error(`Unsupported algorithm: ${i}`);const n={alg:i,typ:s};t.kid&&(n.kid=t.kid);const u=c.encode(JSON.stringify(n)),o=c.encode(JSON.stringify(e)),g=`${u}.${o}`,v=f[i].sign(g,r);return`${u}.${o}.${v}`},h=(e,r,t={})=>{let i;try{i=A(e)}catch(d){return{valid:!1,error:{reason:d.message,code:"INVALID_TOKEN"}}}const{header:s,payload:n,signature:u}=i,o=s.alg;if(!(o in f))return{valid:!1,error:{reason:`Unsupported or unknown algorithm: ${s.alg}`,code:"INVALID_ALGORITHM"}};if(t.algorithms&&t.algorithms.length>0&&!t.algorithms.includes(o))return{valid:!1,error:{reason:`Algorithm "${o}" is not in the allowed algorithms list`,code:"ALGORITHM_NOT_ALLOWED"}};if(s.typ!==void 0&&s.typ!=="JWT")return{valid:!1,error:{reason:`Invalid token type: expected 'JWT', got '${s.typ}'`,code:"INVALID_TYPE"}};const g=`${c.encode(JSON.stringify(s))}.${c.encode(JSON.stringify(n))}`;if(!f[o].verify(g,r,u))return{valid:!1,error:{reason:"Signature verification failed",code:"INVALID_SIGNATURE"}};const l=Math.floor(Date.now()/1e3),S=t.clockSkew??0;if(!t.ignoreExpiration&&n.exp!==void 0&&l>n.exp+S)return{valid:!1,error:{reason:"Token expired",code:"TOKEN_EXPIRED"}};if(n.nbf!==void 0&&l+S<n.nbf)return{valid:!1,error:{reason:"Token not yet valid",code:"TOKEN_NOT_ACTIVE"}};if(n.iat!==void 0&&l+S<n.iat)return{valid:!1,error:{reason:"Token issued in the future",code:"TOKEN_FUTURE_ISSUED"}};if(t.maxTokenAge!==void 0&&n.iat!==void 0){const d=l-n.iat;if(d>t.maxTokenAge)return{valid:!1,error:{reason:`Token age (${d}s) exceeds maximum allowed age (${t.maxTokenAge}s)`,code:"TOKEN_TOO_OLD"}}}if(t.issuer!==void 0){if(n.iss===void 0)return{valid:!1,error:{reason:'Token missing required issuer claim ("iss")',code:"MISSING_ISSUER"}};if(t.issuer!==n.iss)return{valid:!1,error:{reason:`Invalid token issuer: expected "${t.issuer}", got "${n.iss}"`,code:"INVALID_ISSUER"}}}if(t.subject!==void 0){if(n.sub===void 0)return{valid:!1,error:{reason:'Token missing required subject claim ("sub")',code:"MISSING_SUBJECT"}};if(t.subject!==n.sub)return{valid:!1,error:{reason:`Invalid token subject: expected "${t.subject}", got "${n.sub}"`,code:"INVALID_SUBJECT"}}}if(t.audience!==void 0){const d=n.aud;if(d===void 0)return{valid:!1,error:{reason:'Token missing required audience claim ("aud")',code:"MISSING_AUDIENCE"}};const I=Array.isArray(t.audience)?t.audience:[t.audience],p=Array.isArray(d)?d:[d];if(!I.some(b=>p.includes(b)))return{valid:!1,error:{reason:"Audience claim mismatch",code:"INVALID_AUDIENCE"}}}if(t.jwtId!==void 0){if(n.jti===void 0)return{valid:!1,error:{reason:'Token missing required JWT ID claim ("jti")',code:"MISSING_JTI"}};if(t.jwtId!==n.jti)return{valid:!1,error:{reason:`Invalid JWT ID: expected "${t.jwtId}", got "${n.jti}"`,code:"INVALID_JTI"}}}return{valid:!0,header:s,payload:n,signature:u}},_={sign:m,verify:h,decode:A,algorithms:f};exports.JWT=_;exports.SignatureAlgorithm=f;exports.SupportedAlgorithms=T;exports.base64Url=c;exports.decode=A;exports.sign=m;exports.verify=h;
2
2
  //# sourceMappingURL=index.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs.js","sources":["../src/index.ts"],"sourcesContent":["import {\n createHmac,\n createSign,\n createVerify,\n type BinaryLike,\n type KeyLike\n} from 'crypto';\n\n// Base64URL helpers (padding-safe)\nexport const base64Url = {\n encode: (input: string | Buffer): string =>\n Buffer.from(input).toString('base64url'),\n\n decode: (input: string): string => {\n // Node.js Buffer handles unpadded base64url since v16, but we normalize for safety\n return Buffer.from(input, 'base64url').toString();\n }\n};\n\n// Standard JWT payload claims\nexport interface JWTPayload {\n /**\n * Issuer\n */\n iss?: string;\n /**\n * Subject\n */\n sub?: string;\n /**\n * Audience\n */\n aud?: string | string[];\n /**\n * Expiration Time (as UNIX timestamp)\n */\n exp?: number;\n /**\n * Not Before (as UNIX timestamp)\n */\n nbf?: number;\n /**\n * Issued At (as UNIX timestamp)\n */\n iat?: number;\n /**\n * JWT ID\n */\n jti?: string;\n /**\n * Session ID\n */\n sid?: string;\n /**\n * Custom claims\n */\n [key: string]: unknown;\n}\n\nexport interface JWTHeader {\n alg: string; // Allow unknown algs during decode\n typ?: string;\n kid?: string;\n}\n\nexport interface JWT {\n header: JWTHeader;\n payload: JWTPayload;\n signature: string;\n}\n\n// Signature algorithms\nexport const SignatureAlgorithm = {\n // HMAC\n HS256: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createHmac('sha256', secret).update(data).digest('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) =>\n createHmac('sha256', secret).update(data).digest('base64url') === signature\n },\n HS384: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createHmac('sha384', secret).update(data).digest('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) =>\n createHmac('sha384', secret).update(data).digest('base64url') === signature\n },\n HS512: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createHmac('sha512', secret).update(data).digest('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) =>\n createHmac('sha512', secret).update(data).digest('base64url') === signature\n },\n\n // RSA (DER-encoded signatures, base64url)\n RS256: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createSign('RSA-SHA256').update(data).end().sign(secret).toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) =>\n createVerify('RSA-SHA256')\n .update(data)\n .end()\n .verify(secret, Buffer.from(signature, 'base64url'))\n },\n RS384: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createSign('RSA-SHA384').update(data).end().sign(secret).toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) =>\n createVerify('RSA-SHA384')\n .update(data)\n .end()\n .verify(secret, Buffer.from(signature, 'base64url'))\n },\n RS512: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createSign('RSA-SHA512').update(data).end().sign(secret).toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) =>\n createVerify('RSA-SHA512')\n .update(data)\n .end()\n .verify(secret, Buffer.from(signature, 'base64url'))\n },\n\n // ECDSA (DER-encoded by default — no dsaEncoding!)\n ES256: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createSign('SHA256').update(data).end().sign(secret).toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) =>\n createVerify('SHA256')\n .update(data)\n .end()\n .verify(secret, Buffer.from(signature, 'base64url'))\n },\n ES384: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createSign('SHA384').update(data).end().sign(secret).toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) =>\n createVerify('SHA384')\n .update(data)\n .end()\n .verify(secret, Buffer.from(signature, 'base64url'))\n },\n ES512: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createSign('SHA512').update(data).end().sign(secret).toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) =>\n createVerify('SHA512')\n .update(data)\n .end()\n .verify(secret, Buffer.from(signature, 'base64url'))\n }\n} as const;\n\nexport type SupportedAlgorithm = keyof typeof SignatureAlgorithm;\n\nexport const SupportedAlgorithms = Object.keys(SignatureAlgorithm) as Array<SupportedAlgorithm>;\n\n/**\n * Decode a JWT string into its parts (without verification)\n */\nexport const decode = (token: string): JWT => {\n const parts = token.split('.');\n if (parts.length !== 3) {\n throw new Error('Invalid JWT: must contain exactly 3 parts separated by \".\"');\n }\n\n const [headerPart, payloadPart, signature] = parts;\n\n if (!headerPart || !payloadPart || !signature) {\n throw new Error('Invalid JWT: empty part detected');\n }\n\n try {\n const header = JSON.parse(base64Url.decode(headerPart)) as JWTHeader;\n const payload = JSON.parse(base64Url.decode(payloadPart)) as JWTPayload;\n return { header, payload, signature };\n } catch (err) {\n throw new Error(`Invalid JWT: malformed header or payload (${(err as Error).message})`);\n }\n};\n\n/**\n * Sign a JWT\n */\nexport const sign = (\n payload: JWTPayload,\n secret: KeyLike,\n options: {\n alg?: SupportedAlgorithm;\n kid?: string;\n typ?: string;\n } = {}\n): string => {\n const alg = options.alg ?? 'HS256';\n const typ = options.typ ?? 'JWT';\n\n if (!(alg in SignatureAlgorithm)) {\n throw new Error(`Unsupported algorithm: ${alg}`);\n }\n\n const header: JWTHeader = { alg, typ };\n if (options.kid) header.kid = options.kid;\n\n const headerEncoded = base64Url.encode(JSON.stringify(header));\n const payloadEncoded = base64Url.encode(JSON.stringify(payload));\n\n const signingInput = `${headerEncoded}.${payloadEncoded}`;\n const signature = SignatureAlgorithm[alg].sign(signingInput, secret);\n\n return `${headerEncoded}.${payloadEncoded}.${signature}`;\n};\n\n/**\n * Verify and validate a JWT\n */\nexport const verify = (\n token: string,\n secret: KeyLike,\n options: {\n ignoreExpiration?: boolean;\n clockSkew?: number; // in seconds, default 0\n } = {}\n):\n | { valid: true; header: JWTHeader; payload: JWTPayload; signature: string }\n | { valid: false; error: { reason: string; code: string } } => {\n let decoded: JWT;\n try {\n decoded = decode(token);\n } catch (err) {\n return {\n valid: false,\n error: {\n reason: (err as Error).message,\n code: 'INVALID_TOKEN'\n }\n };\n }\n\n const { header, payload, signature } = decoded;\n\n // Validate algorithm\n const alg = header.alg as SupportedAlgorithm;\n if (!(alg in SignatureAlgorithm)) {\n return {\n valid: false,\n error: {\n reason: `Unsupported or unknown algorithm: ${header.alg}`,\n code: 'INVALID_ALGORITHM'\n }\n };\n }\n\n // Optional: validate 'typ' header\n if (header.typ && header.typ !== 'JWT') {\n return {\n valid: false,\n error: {\n reason: `Invalid token type: expected 'JWT', got '${header.typ}'`,\n code: 'INVALID_TYPE'\n }\n };\n }\n\n // Verify signature\n const signingInput = `${base64Url.encode(JSON.stringify(header))}.${base64Url.encode(JSON.stringify(payload))}`;\n const isValidSignature = SignatureAlgorithm[alg].verify(signingInput, secret, signature);\n\n if (!isValidSignature) {\n return {\n valid: false,\n error: {\n reason: \"Signature verification failed\",\n code: 'INVALID_SIGNATURE'\n }\n };\n }\n\n // Time validation\n const now = Math.floor(Date.now() / 1000);\n const skew = options.clockSkew ?? 0;\n\n if (!options.ignoreExpiration) {\n if (payload.exp !== undefined && now > payload.exp + skew) {\n return {\n valid: false,\n error: {\n reason: 'Token expired',\n code: 'TOKEN_EXPIRED'\n }\n };\n }\n }\n\n if (payload.nbf !== undefined && now + skew < payload.nbf) {\n return {\n valid: false,\n error: {\n reason: 'Token not yet valid',\n code: 'TOKEN_NOT_ACTIVE'\n }\n };\n }\n\n if (payload.iat !== undefined && now + skew < payload.iat) {\n return {\n valid: false,\n error: {\n reason: 'Token issued in the future',\n code: 'TOKEN_FUTURE_ISSUED'\n }\n };\n }\n\n return { valid: true, header, payload, signature };\n};\n\n// Optional: namespace export (not default)\nexport const JWT = {\n sign,\n verify,\n decode,\n algorithms: SignatureAlgorithm\n};\n"],"names":["base64Url","input","SignatureAlgorithm","data","secret","createHmac","signature","createSign","createVerify","SupportedAlgorithms","decode","token","parts","headerPart","payloadPart","header","payload","err","sign","options","alg","typ","headerEncoded","payloadEncoded","signingInput","verify","decoded","now","skew","JWT"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs.js","sources":["../src/index.ts"],"sourcesContent":["import crypto, {\n createHmac,\n createSign,\n createVerify,\n sign as cryptoSign,\n verify as cryptoVerify,\n timingSafeEqual,\n type BinaryLike,\n type KeyLike\n} from 'crypto';\n\n// Base64URL helpers (padding-safe)\nexport const base64Url = {\n encode: (input: string | Buffer): string =>\n Buffer.from(input).toString('base64url'),\n\n decode: (input: string): string => {\n // Node.js Buffer handles unpadded base64url since v16, but we normalize for safety\n return Buffer.from(input, 'base64url').toString();\n }\n};\n\n// Timing-safe string comparison to prevent timing attacks\nconst timingSafeCompare = (a: string, b: string): boolean => {\n if (a.length !== b.length) {\n return false;\n }\n return timingSafeEqual(Buffer.from(a), Buffer.from(b));\n};\n\n// Standard JWT payload claims\nexport interface JWTPayload {\n /**\n * Issuer\n */\n iss?: string;\n /**\n * Subject\n */\n sub?: string;\n /**\n * Audience\n */\n aud?: string | string[];\n /**\n * Expiration Time (as UNIX timestamp)\n */\n exp?: number;\n /**\n * Not Before (as UNIX timestamp)\n */\n nbf?: number;\n /**\n * Issued At (as UNIX timestamp)\n */\n iat?: number;\n /**\n * JWT ID\n */\n jti?: string;\n /**\n * Session ID\n */\n sid?: string;\n\n /**\n * Custom claims\n */\n [key: string]: unknown;\n}\n\nexport interface JWTHeader {\n alg: string; // Allow unknown algs during decode\n typ?: string;\n kid?: string;\n}\n\nexport interface JWT {\n header: JWTHeader;\n payload: JWTPayload;\n signature: string;\n}\n\n// Signature algorithms\nexport const SignatureAlgorithm = {\n // HMAC\n HS256: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createHmac('sha256', secret).update(data).digest('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) => {\n const expected = createHmac('sha256', secret).update(data).digest('base64url');\n return timingSafeCompare(expected, signature);\n }\n },\n HS384: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createHmac('sha384', secret).update(data).digest('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) => {\n const expected = createHmac('sha384', secret).update(data).digest('base64url');\n return timingSafeCompare(expected, signature);\n }\n },\n HS512: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createHmac('sha512', secret).update(data).digest('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) => {\n const expected = createHmac('sha512', secret).update(data).digest('base64url');\n return timingSafeCompare(expected, signature);\n }\n },\n\n // RSA (DER-encoded signatures, base64url)\n RS256: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createSign('RSA-SHA256').update(data).end().sign(secret).toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) => {\n try {\n return createVerify('RSA-SHA256')\n .update(data)\n .end()\n .verify(secret, Buffer.from(signature, 'base64url'));\n } catch {\n return false;\n }\n }\n },\n RS384: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createSign('RSA-SHA384').update(data).end().sign(secret).toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) => {\n try {\n return createVerify('RSA-SHA384')\n .update(data)\n .end()\n .verify(secret, Buffer.from(signature, 'base64url'));\n } catch {\n return false;\n }\n }\n },\n RS512: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createSign('RSA-SHA512').update(data).end().sign(secret).toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) => {\n try {\n return createVerify('RSA-SHA512')\n .update(data)\n .end()\n .verify(secret, Buffer.from(signature, 'base64url'));\n } catch {\n return false;\n }\n }\n },\n\n // ECDSA (DER-encoded by default — no dsaEncoding!)\n ES256: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createSign('SHA256').update(data).end().sign(secret).toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) => {\n try {\n return createVerify('SHA256')\n .update(data)\n .end()\n .verify(secret, Buffer.from(signature, 'base64url'));\n } catch {\n return false;\n }\n }\n },\n ES384: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createSign('SHA384').update(data).end().sign(secret).toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) => {\n try {\n return createVerify('SHA384')\n .update(data)\n .end()\n .verify(secret, Buffer.from(signature, 'base64url'));\n } catch {\n return false;\n }\n }\n },\n ES512: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createSign('SHA512').update(data).end().sign(secret).toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) => {\n try {\n return createVerify('SHA512')\n .update(data)\n .end()\n .verify(secret, Buffer.from(signature, 'base64url'));\n } catch {\n return false;\n }\n }\n },\n ES256K: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createSign('SHA256').update(data).end().sign(secret).toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) => {\n try {\n return createVerify('SHA256')\n .update(data)\n .end()\n .verify(secret, Buffer.from(signature, 'base64url'));\n } catch {\n return false;\n }\n }\n },\n PS256: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createSign('RSA-SHA256')\n .update(data)\n .end()\n .sign({\n //@ts-ignore\n key: secret,\n padding: crypto.constants.RSA_PKCS1_PSS_PADDING,\n saltLength: 32\n })\n .toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) => {\n try {\n return createVerify('RSA-SHA256')\n .update(data)\n .end()\n .verify({\n //@ts-ignore\n key: secret,\n padding: crypto.constants.RSA_PKCS1_PSS_PADDING,\n saltLength: 32\n }, Buffer.from(signature, 'base64url'));\n } catch {\n return false;\n }\n }\n },\n PS384: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createSign('RSA-SHA384')\n .update(data)\n .end()\n .sign({\n //@ts-ignore\n key: secret,\n padding: crypto.constants.RSA_PKCS1_PSS_PADDING,\n saltLength: 48\n })\n .toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) => {\n try {\n return createVerify('RSA-SHA384')\n .update(data)\n .end()\n .verify({\n //@ts-ignore\n key: secret,\n padding: crypto.constants.RSA_PKCS1_PSS_PADDING,\n saltLength: 48\n }, Buffer.from(signature, 'base64url'));\n } catch {\n return false;\n }\n }\n },\n PS512: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n createSign('RSA-SHA512')\n .update(data)\n .end()\n .sign({\n //@ts-ignore\n key: secret,\n padding: crypto.constants.RSA_PKCS1_PSS_PADDING,\n saltLength: 64\n })\n .toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) => {\n try {\n return createVerify('RSA-SHA512')\n .update(data)\n .end()\n .verify({\n //@ts-ignore\n key: secret,\n padding: crypto.constants.RSA_PKCS1_PSS_PADDING,\n saltLength: 64\n }, Buffer.from(signature, 'base64url'));\n } catch {\n return false;\n }\n }\n },\n EdDSA: {\n sign: (data: BinaryLike, secret: KeyLike) =>\n cryptoSign(null, typeof data === 'string' ? Buffer.from(data, 'utf8') : data, secret)\n .toString('base64url'),\n verify: (data: BinaryLike, secret: KeyLike, signature: string) => {\n try {\n return cryptoVerify(\n null,\n typeof data === 'string' ? Buffer.from(data, 'utf8') : data,\n secret,\n Buffer.from(signature, 'base64url')\n );\n } catch {\n return false;\n }\n }\n }\n} as const;\n\nexport type SupportedAlgorithm = keyof typeof SignatureAlgorithm;\n\nexport const SupportedAlgorithms = Object.keys(SignatureAlgorithm) as Array<SupportedAlgorithm>;\n\n/**\n * Decode a JWT string into its parts (without verification)\n */\nexport const decode = (token: string): JWT => {\n const parts = token.split('.');\n if (parts.length !== 3) {\n throw new Error('Invalid JWT: must contain exactly 3 parts separated by \".\"');\n }\n\n const [headerPart, payloadPart, signature] = parts;\n\n if (!headerPart || !payloadPart || !signature) {\n throw new Error('Invalid JWT: empty part detected');\n }\n\n try {\n const header = JSON.parse(base64Url.decode(headerPart)) as JWTHeader;\n const payload = JSON.parse(base64Url.decode(payloadPart)) as JWTPayload;\n return {header, payload, signature};\n } catch (err) {\n throw new Error(`Invalid JWT: malformed header or payload (${(err as Error).message})`);\n }\n};\n\n/**\n * Sign a JWT\n */\nexport const sign = (\n payload: JWTPayload,\n secret: KeyLike,\n options: {\n alg?: SupportedAlgorithm;\n kid?: string;\n typ?: string;\n } = {}\n): string => {\n const alg = options.alg ?? 'HS256';\n const typ = options.typ ?? 'JWT';\n\n if (!(alg in SignatureAlgorithm)) {\n throw new Error(`Unsupported algorithm: ${alg}`);\n }\n\n const header: JWTHeader = {alg, typ};\n if (options.kid) header.kid = options.kid;\n\n const headerEncoded = base64Url.encode(JSON.stringify(header));\n const payloadEncoded = base64Url.encode(JSON.stringify(payload));\n\n const signingInput = `${headerEncoded}.${payloadEncoded}`;\n const signature = SignatureAlgorithm[alg].sign(signingInput, secret);\n\n return `${headerEncoded}.${payloadEncoded}.${signature}`;\n};\n\n/**\n * Verify and validate a JWT\n */\nexport const verify = (\n token: string,\n secret: KeyLike,\n options: {\n algorithms?: SupportedAlgorithm[]; // Whitelist of allowed algorithms\n issuer?: string;\n subject?: string;\n audience?: string | string[];\n jwtId?: string;\n ignoreExpiration?: boolean;\n clockSkew?: number; // in seconds, default 0\n maxTokenAge?: number; // Maximum age in seconds\n } = {}\n):\n | { valid: true; header: JWTHeader; payload: JWTPayload; signature: string }\n | { valid: false; error: { reason: string; code: string } } => {\n let decoded: JWT;\n try {\n decoded = decode(token);\n } catch (err) {\n return {\n valid: false,\n error: {\n reason: (err as Error).message,\n code: 'INVALID_TOKEN'\n }\n };\n }\n\n const {header, payload, signature} = decoded;\n\n // Validate algorithm\n const alg = header.alg as SupportedAlgorithm;\n if (!(alg in SignatureAlgorithm)) {\n return {\n valid: false,\n error: {\n reason: `Unsupported or unknown algorithm: ${header.alg}`,\n code: 'INVALID_ALGORITHM'\n }\n };\n }\n\n // Algorithm whitelist validation (prevents algorithm confusion attacks)\n if (options.algorithms && options.algorithms.length > 0) {\n if (!options.algorithms.includes(alg)) {\n return {\n valid: false,\n error: {\n reason: `Algorithm \"${alg}\" is not in the allowed algorithms list`,\n code: 'ALGORITHM_NOT_ALLOWED'\n }\n };\n }\n }\n\n // Validate 'typ' header (must be 'JWT' if present)\n if (header.typ !== undefined && header.typ !== 'JWT') {\n return {\n valid: false,\n error: {\n reason: `Invalid token type: expected 'JWT', got '${header.typ}'`,\n code: 'INVALID_TYPE'\n }\n };\n }\n\n // Verify signature\n const signingInput = `${base64Url.encode(JSON.stringify(header))}.${base64Url.encode(JSON.stringify(payload))}`;\n const isValidSignature = SignatureAlgorithm[alg].verify(signingInput, secret, signature);\n\n if (!isValidSignature) {\n return {\n valid: false,\n error: {\n reason: \"Signature verification failed\",\n code: 'INVALID_SIGNATURE'\n }\n };\n }\n\n // Time validation\n const now = Math.floor(Date.now() / 1000);\n const skew = options.clockSkew ?? 0;\n\n if (!options.ignoreExpiration) {\n if (payload.exp !== undefined && now > payload.exp + skew) {\n return {\n valid: false,\n error: {\n reason: 'Token expired',\n code: 'TOKEN_EXPIRED'\n }\n };\n }\n }\n\n if (payload.nbf !== undefined && now + skew < payload.nbf) {\n return {\n valid: false,\n error: {\n reason: 'Token not yet valid',\n code: 'TOKEN_NOT_ACTIVE'\n }\n };\n }\n\n if (payload.iat !== undefined && now + skew < payload.iat) {\n return {\n valid: false,\n error: {\n reason: 'Token issued in the future',\n code: 'TOKEN_FUTURE_ISSUED'\n }\n };\n }\n\n // Maximum token age validation\n if (options.maxTokenAge !== undefined && payload.iat !== undefined) {\n const tokenAge = now - payload.iat;\n if (tokenAge > options.maxTokenAge) {\n return {\n valid: false,\n error: {\n reason: `Token age (${tokenAge}s) exceeds maximum allowed age (${options.maxTokenAge}s)`,\n code: 'TOKEN_TOO_OLD'\n }\n };\n }\n }\n\n // --- Claim validations (only if options provided) ---\n\n // Issuer (`iss`)\n if (options.issuer !== undefined) {\n if (payload.iss === undefined) {\n return {\n valid: false,\n error: {\n reason: 'Token missing required issuer claim (\"iss\")',\n code: 'MISSING_ISSUER'\n }\n };\n }\n if (options.issuer !== payload.iss) {\n return {\n valid: false,\n error: {\n reason: `Invalid token issuer: expected \"${options.issuer}\", got \"${payload.iss}\"`,\n code: 'INVALID_ISSUER'\n }\n };\n }\n }\n\n // Subject (`sub`)\n if (options.subject !== undefined) {\n if (payload.sub === undefined) {\n return {\n valid: false,\n error: {\n reason: 'Token missing required subject claim (\"sub\")',\n code: 'MISSING_SUBJECT'\n }\n };\n }\n if (options.subject !== payload.sub) {\n return {\n valid: false,\n error: {\n reason: `Invalid token subject: expected \"${options.subject}\", got \"${payload.sub}\"`,\n code: 'INVALID_SUBJECT'\n }\n };\n }\n }\n\n // Audience (`aud`)\n if (options.audience !== undefined) {\n const aud = payload.aud;\n if (aud === undefined) {\n return {\n valid: false,\n error: {\n reason: 'Token missing required audience claim (\"aud\")',\n code: 'MISSING_AUDIENCE'\n }\n };\n }\n\n const expectedAud = Array.isArray(options.audience) ? options.audience : [options.audience];\n const tokenAud = Array.isArray(aud) ? aud : [aud];\n\n const hasMatch = expectedAud.some(a => tokenAud.includes(a));\n if (!hasMatch) {\n return {\n valid: false,\n error: {\n reason: 'Audience claim mismatch',\n code: 'INVALID_AUDIENCE'\n }\n };\n }\n }\n\n // JWT ID (`jti`)\n if (options.jwtId !== undefined) {\n if (payload.jti === undefined) {\n return {\n valid: false,\n error: {\n reason: 'Token missing required JWT ID claim (\"jti\")',\n code: 'MISSING_JTI'\n }\n };\n }\n if (options.jwtId !== payload.jti) {\n return {\n valid: false,\n error: {\n reason: `Invalid JWT ID: expected \"${options.jwtId}\", got \"${payload.jti}\"`,\n code: 'INVALID_JTI'\n }\n };\n }\n }\n\n return {valid: true, header, payload, signature};\n};\n\n// Optional: namespace export\nexport const JWT = {\n sign,\n verify,\n decode,\n algorithms: SignatureAlgorithm\n};\n"],"names":["base64Url","input","timingSafeCompare","a","b","timingSafeEqual","SignatureAlgorithm","data","secret","createHmac","signature","expected","createSign","createVerify","crypto","cryptoSign","cryptoVerify","SupportedAlgorithms","decode","token","parts","headerPart","payloadPart","header","payload","err","sign","options","alg","typ","headerEncoded","payloadEncoded","signingInput","verify","decoded","now","skew","tokenAge","aud","expectedAud","tokenAud","JWT"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -88,6 +88,26 @@ export declare const SignatureAlgorithm: {
88
88
  readonly sign: (data: BinaryLike, secret: KeyLike) => string;
89
89
  readonly verify: (data: BinaryLike, secret: KeyLike, signature: string) => boolean;
90
90
  };
91
+ readonly ES256K: {
92
+ readonly sign: (data: BinaryLike, secret: KeyLike) => string;
93
+ readonly verify: (data: BinaryLike, secret: KeyLike, signature: string) => boolean;
94
+ };
95
+ readonly PS256: {
96
+ readonly sign: (data: BinaryLike, secret: KeyLike) => string;
97
+ readonly verify: (data: BinaryLike, secret: KeyLike, signature: string) => boolean;
98
+ };
99
+ readonly PS384: {
100
+ readonly sign: (data: BinaryLike, secret: KeyLike) => string;
101
+ readonly verify: (data: BinaryLike, secret: KeyLike, signature: string) => boolean;
102
+ };
103
+ readonly PS512: {
104
+ readonly sign: (data: BinaryLike, secret: KeyLike) => string;
105
+ readonly verify: (data: BinaryLike, secret: KeyLike, signature: string) => boolean;
106
+ };
107
+ readonly EdDSA: {
108
+ readonly sign: (data: BinaryLike, secret: KeyLike) => string;
109
+ readonly verify: (data: BinaryLike, secret: KeyLike, signature: string) => boolean;
110
+ };
91
111
  };
92
112
  export type SupportedAlgorithm = keyof typeof SignatureAlgorithm;
93
113
  export declare const SupportedAlgorithms: Array<SupportedAlgorithm>;
@@ -107,8 +127,14 @@ export declare const sign: (payload: JWTPayload, secret: KeyLike, options?: {
107
127
  * Verify and validate a JWT
108
128
  */
109
129
  export declare const verify: (token: string, secret: KeyLike, options?: {
130
+ algorithms?: SupportedAlgorithm[];
131
+ issuer?: string;
132
+ subject?: string;
133
+ audience?: string | string[];
134
+ jwtId?: string;
110
135
  ignoreExpiration?: boolean;
111
136
  clockSkew?: number;
137
+ maxTokenAge?: number;
112
138
  }) => {
113
139
  valid: true;
114
140
  header: JWTHeader;
@@ -128,8 +154,14 @@ export declare const JWT: {
128
154
  typ?: string;
129
155
  }) => string;
130
156
  verify: (token: string, secret: KeyLike, options?: {
157
+ algorithms?: SupportedAlgorithm[];
158
+ issuer?: string;
159
+ subject?: string;
160
+ audience?: string | string[];
161
+ jwtId?: string;
131
162
  ignoreExpiration?: boolean;
132
163
  clockSkew?: number;
164
+ maxTokenAge?: number;
133
165
  }) => {
134
166
  valid: true;
135
167
  header: JWTHeader;
@@ -180,5 +212,25 @@ export declare const JWT: {
180
212
  readonly sign: (data: BinaryLike, secret: KeyLike) => string;
181
213
  readonly verify: (data: BinaryLike, secret: KeyLike, signature: string) => boolean;
182
214
  };
215
+ readonly ES256K: {
216
+ readonly sign: (data: BinaryLike, secret: KeyLike) => string;
217
+ readonly verify: (data: BinaryLike, secret: KeyLike, signature: string) => boolean;
218
+ };
219
+ readonly PS256: {
220
+ readonly sign: (data: BinaryLike, secret: KeyLike) => string;
221
+ readonly verify: (data: BinaryLike, secret: KeyLike, signature: string) => boolean;
222
+ };
223
+ readonly PS384: {
224
+ readonly sign: (data: BinaryLike, secret: KeyLike) => string;
225
+ readonly verify: (data: BinaryLike, secret: KeyLike, signature: string) => boolean;
226
+ };
227
+ readonly PS512: {
228
+ readonly sign: (data: BinaryLike, secret: KeyLike) => string;
229
+ readonly verify: (data: BinaryLike, secret: KeyLike, signature: string) => boolean;
230
+ };
231
+ readonly EdDSA: {
232
+ readonly sign: (data: BinaryLike, secret: KeyLike) => string;
233
+ readonly verify: (data: BinaryLike, secret: KeyLike, signature: string) => boolean;
234
+ };
183
235
  };
184
236
  };