@sourceregistry/node-jwt 1.2.1 → 1.3.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 +128 -147
- package/dist/index-CSRWSLal.cjs +2 -0
- package/dist/index-CSRWSLal.cjs.map +1 -0
- package/dist/index-DyXdSqEc.js +515 -0
- package/dist/index-DyXdSqEc.js.map +1 -0
- package/dist/index.cjs.js +1 -1
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.d.ts +2 -236
- package/dist/index.es.js +18 -366
- package/dist/index.es.js.map +1 -1
- package/dist/promises.cjs.js +1 -1
- package/dist/promises.cjs.js.map +1 -1
- package/dist/promises.d.ts +2 -115
- package/dist/promises.es.js +34 -15
- package/dist/promises.es.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,40 +1,47 @@
|
|
|
1
1
|
# 🔐 @sourceregistry/node-jwt
|
|
2
|
+
|
|
2
3
|
[](https://www.npmjs.com/package/@sourceregistry/node-jwt)
|
|
3
4
|
[](https://github.com/SourceRegistry/node-jwt/blob/main/LICENSE)
|
|
4
5
|
[](https://github.com/SourceRegistry/node-jwt/actions)
|
|
5
6
|
[](https://codecov.io/gh/SourceRegistry/node-jwt)
|
|
6
7
|
|
|
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.
|
|
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, EdDSA, RSASSA-PSS), **automatic algorithm detection**, **JWK/JWKS**, and full claim validation.
|
|
8
9
|
|
|
9
|
-
✨ **Why another JWT library?**
|
|
10
|
+
✨ **Why another JWT library?**
|
|
10
11
|
Most JWT libraries are bloated, have security pitfalls, or lack proper TypeScript support. This library is:
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
13
|
+
* **Tiny**
|
|
14
|
+
* **Secure by default**
|
|
15
|
+
* **TypeScript-first** with full JSDoc
|
|
16
|
+
* **Zero external dependencies**
|
|
17
|
+
* **100% test coverage**
|
|
18
|
+
* **Dual API**: Sync and Promise-based
|
|
19
|
+
* **Automatic algorithm detection based on key type**
|
|
20
|
+
* **Full JWK/JWKS support** (`import/export`, `toPublicJWK`, `x5c/x5t`, RFC 7638 thumbprints, kid-based key selection)
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 📦 Installation
|
|
18
25
|
|
|
19
|
-
📦 **Installation**
|
|
20
26
|
```bash
|
|
21
27
|
npm install @sourceregistry/node-jwt
|
|
22
28
|
```
|
|
29
|
+
|
|
23
30
|
Requires Node.js ≥ 16
|
|
24
31
|
|
|
25
32
|
---
|
|
26
33
|
|
|
27
|
-
🚀
|
|
34
|
+
## 🚀 Quick Start
|
|
28
35
|
|
|
29
36
|
### Sync API (default)
|
|
37
|
+
|
|
30
38
|
```ts
|
|
31
39
|
import { sign, verify, decode } from '@sourceregistry/node-jwt';
|
|
32
40
|
|
|
33
|
-
// Sign
|
|
41
|
+
// Sign (algorithm auto-detected)
|
|
34
42
|
const token = sign(
|
|
35
43
|
{ sub: '1234567890', name: 'John Doe', iat: Math.floor(Date.now() / 1000) },
|
|
36
|
-
'your-secret-key'
|
|
37
|
-
{ alg: 'HS256' }
|
|
44
|
+
'your-secret-key'
|
|
38
45
|
);
|
|
39
46
|
|
|
40
47
|
// Verify
|
|
@@ -50,19 +57,19 @@ const { header, payload, signature } = decode(token);
|
|
|
50
57
|
```
|
|
51
58
|
|
|
52
59
|
### Promise API (`/promises`)
|
|
60
|
+
|
|
53
61
|
```ts
|
|
54
62
|
import { sign, verify, decode } from '@sourceregistry/node-jwt/promises';
|
|
55
63
|
|
|
56
|
-
// Sign
|
|
64
|
+
// Sign (algorithm auto-detected)
|
|
57
65
|
const token = await sign(
|
|
58
66
|
{ sub: '1234567890', name: 'John Doe', iat: Math.floor(Date.now() / 1000) },
|
|
59
|
-
'your-secret-key'
|
|
60
|
-
{ alg: 'HS256' }
|
|
67
|
+
'your-secret-key'
|
|
61
68
|
);
|
|
62
69
|
|
|
63
70
|
// Verify
|
|
64
71
|
try {
|
|
65
|
-
const { payload
|
|
72
|
+
const { payload } = await verify(token, 'your-secret-key', {
|
|
66
73
|
issuer: 'https://example.com',
|
|
67
74
|
audience: 'my-app',
|
|
68
75
|
algorithms: ['HS256']
|
|
@@ -78,172 +85,146 @@ const { header, payload, signature } = await decode(token);
|
|
|
78
85
|
|
|
79
86
|
---
|
|
80
87
|
|
|
81
|
-
|
|
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`).
|
|
88
|
+
## 🧠 Algorithm Autodetection (New)
|
|
101
89
|
|
|
102
|
-
|
|
90
|
+
When `options.alg` is **omitted**, the library automatically selects the correct JWT algorithm **based on the signing key**.
|
|
103
91
|
|
|
104
|
-
|
|
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
|
|
92
|
+
### 🔑 Autodetection Rules
|
|
119
93
|
|
|
120
|
-
|
|
94
|
+
| Key Type | Detection Logic | Selected Algorithm |
|
|
95
|
+
| ------------------------------- | --------------------- | --------------------------- |
|
|
96
|
+
| Symmetric (`string` / `Buffer`) | Default HMAC | `HS256` |
|
|
97
|
+
| RSA private key | PKCS#1 v1.5 | `RS256` |
|
|
98
|
+
| RSA-PSS private key | Hash algorithm in key | `PS256` / `PS384` / `PS512` |
|
|
99
|
+
| EC P-256 (`prime256v1`) | Curve name | `ES256` |
|
|
100
|
+
| EC P-384 (`secp384r1`) | Curve name | `ES384` |
|
|
101
|
+
| EC P-521 (`secp521r1`) | Curve name | `ES512` |
|
|
102
|
+
| EC secp256k1 | Curve name | `ES256K` |
|
|
103
|
+
| Ed25519 | Key type | `EdDSA` |
|
|
104
|
+
|
|
105
|
+
> 💡 Node.js exposes OpenSSL curve names (`prime256v1`, `secp384r1`, etc.).
|
|
106
|
+
> These are automatically normalized to JOSE algorithms.
|
|
121
107
|
|
|
122
|
-
|
|
108
|
+
### ❌ Autodetection Errors
|
|
123
109
|
|
|
124
|
-
|
|
110
|
+
Autodetection fails for unsupported keys:
|
|
125
111
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
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 |
|
|
112
|
+
* Unsupported EC curve
|
|
113
|
+
* Unsupported RSA-PSS hash algorithm (e.g. `sha1`)
|
|
114
|
+
* Unsupported asymmetric key type (e.g. DSA)
|
|
131
115
|
|
|
132
116
|
---
|
|
133
117
|
|
|
134
|
-
|
|
135
|
-
Sign a JWT.
|
|
118
|
+
## 🔑 Supported Algorithms
|
|
136
119
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
120
|
+
| Algorithm | Type | Secret Type |
|
|
121
|
+
| --------------------- | ----------------- | -------------------- |
|
|
122
|
+
| HS256 / HS384 / HS512 | HMAC | `string \| Buffer` |
|
|
123
|
+
| RS256 / RS384 / RS512 | RSA | Private / Public key |
|
|
124
|
+
| PS256 / PS384 / PS512 | RSA-PSS | Private / Public key |
|
|
125
|
+
| ES256 / ES384 / ES512 | ECDSA | Private / Public key |
|
|
126
|
+
| ES256K | ECDSA (secp256k1) | Private / Public key |
|
|
127
|
+
| EdDSA | Ed25519 | Private / Public key |
|
|
143
128
|
|
|
144
|
-
|
|
129
|
+
> Keys may be PEM, DER, JWK, or Node.js `KeyObject`.
|
|
145
130
|
|
|
146
131
|
---
|
|
147
132
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
- `
|
|
152
|
-
|
|
153
|
-
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
- `jwtId`: Required value for the `jti` claim
|
|
159
|
-
- `ignoreExpiration`: Skip `exp` check (default: `false`)
|
|
160
|
-
- `clockSkew`: Tolerance in seconds for time validation (default: `0`)
|
|
161
|
-
- `maxTokenAge`: Maximum allowed token age in seconds (from `iat`)
|
|
162
|
-
|
|
163
|
-
#### Sync Usage:
|
|
164
|
-
```ts
|
|
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
|
-
```
|
|
133
|
+
## 🧩 JWK / JWKS Support
|
|
134
|
+
|
|
135
|
+
* Import/export **JWK**: `importJWK()`, `exportJWK()`
|
|
136
|
+
* Convert to **public-only JWK**: `toPublicJWK()`
|
|
137
|
+
* Compute **RFC 7638 thumbprint**: `getJWKThumbprint()`
|
|
138
|
+
* Support **x5c/x5t** (X.509 cert chain + SHA-1 thumbprint)
|
|
139
|
+
* Normalize **JWKS** with auto-generated `kid` and `x5t`
|
|
140
|
+
* Resolve keys from **JWKS** by `kid` for verification
|
|
141
|
+
|
|
142
|
+
### 🔹 Example: JWKS Key Selection
|
|
172
143
|
|
|
173
|
-
#### Promise Usage:
|
|
174
144
|
```ts
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
145
|
+
import { JWKS, JWK } from '@sourceregistry/node-jwt';
|
|
146
|
+
|
|
147
|
+
const keyPair = generateKeyPairSync('rsa', { modulusLength: 2048 });
|
|
148
|
+
const jwk = JWK.toPublic(keyPair.publicKey);
|
|
149
|
+
const jwks = JWKS.normalize({ keys: [jwk] });
|
|
150
|
+
|
|
151
|
+
// Retrieve key by kid
|
|
152
|
+
const keyObject = JWKS.toKeyObject(jwks, jwk.kid);
|
|
181
153
|
```
|
|
154
|
+
---
|
|
182
155
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
- `MISSING_ISSUER` / `INVALID_ISSUER`
|
|
194
|
-
- `MISSING_SUBJECT` / `INVALID_SUBJECT`
|
|
195
|
-
- `MISSING_AUDIENCE` / `INVALID_AUDIENCE`
|
|
196
|
-
- `MISSING_JTI` / `INVALID_JTI`
|
|
156
|
+
## 🛡️ Security Features
|
|
157
|
+
|
|
158
|
+
* ✅ Safe algorithm autodetection
|
|
159
|
+
* ✅ Strict algorithm whitelisting (`algorithms` option)
|
|
160
|
+
* ✅ Full RSASSA-PSS and Ed25519 support
|
|
161
|
+
* ✅ Time claim validation (`exp`, `nbf`, `iat`) with clock skew
|
|
162
|
+
* ✅ Claim validation (`iss`, `sub`, `aud`, `jti`)
|
|
163
|
+
* ✅ Maximum token age enforcement
|
|
164
|
+
* ✅ Timing-safe signature comparison
|
|
165
|
+
* ✅ No insecure defaults
|
|
197
166
|
|
|
198
167
|
---
|
|
199
168
|
|
|
169
|
+
## 📚 API Reference
|
|
170
|
+
|
|
171
|
+
### `sign(payload, secret, options?)`
|
|
172
|
+
|
|
173
|
+
* `alg` *(optional)* — If omitted, algorithm is auto-detected
|
|
174
|
+
* `kid` — Key ID
|
|
175
|
+
* `typ` — Token type (default: `"JWT"`)
|
|
176
|
+
|
|
177
|
+
### `verify(token, secret, options?)`
|
|
178
|
+
|
|
179
|
+
Includes algorithm whitelist protection and full claim validation.
|
|
180
|
+
|
|
181
|
+
**Error Codes include:**
|
|
182
|
+
|
|
183
|
+
* `INVALID_TOKEN`
|
|
184
|
+
* `INVALID_ALGORITHM`
|
|
185
|
+
* `ALGORITHM_NOT_ALLOWED`
|
|
186
|
+
* `INVALID_SIGNATURE`
|
|
187
|
+
* `TOKEN_EXPIRED`
|
|
188
|
+
* `TOKEN_NOT_ACTIVE`
|
|
189
|
+
* `TOKEN_TOO_OLD`
|
|
190
|
+
* `MISSING_*` / `INVALID_*`
|
|
191
|
+
|
|
200
192
|
### `decode(token)`
|
|
201
|
-
Decode a JWT without verification (**use with caution!**).
|
|
202
193
|
|
|
203
|
-
|
|
204
|
-
- Returns: `{ header, payload, signature }`
|
|
205
|
-
- Throws on malformed tokens (sync) / Rejects (promise)
|
|
194
|
+
Decode a JWT without verification (**unsafe**).
|
|
206
195
|
|
|
207
196
|
---
|
|
208
197
|
|
|
209
|
-
🧪
|
|
210
|
-
|
|
198
|
+
## 🧪 Testing
|
|
199
|
+
|
|
200
|
+
* 100% branch coverage
|
|
201
|
+
* All algorithms + autodetection paths
|
|
202
|
+
* All failure modes
|
|
203
|
+
* Sync + Promise APIs
|
|
204
|
+
* Full JWK/JWKS coverage (import/export, x5c/x5t, thumbprint, kid selection)
|
|
205
|
+
|
|
211
206
|
```bash
|
|
212
207
|
npm test
|
|
213
208
|
npm run test:coverage
|
|
214
209
|
```
|
|
215
210
|
|
|
216
|
-
Tests include:
|
|
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
|
|
221
|
-
- Malformed token handling
|
|
222
|
-
- Signature verification (including timing-safe comparison)
|
|
223
|
-
- Custom claims
|
|
224
|
-
- Both sync and promise APIs
|
|
225
|
-
|
|
226
211
|
---
|
|
227
212
|
|
|
228
|
-
📦
|
|
229
|
-
This package provides two entrypoints:
|
|
213
|
+
## 📦 Exports
|
|
230
214
|
|
|
231
|
-
| Import
|
|
232
|
-
|
|
233
|
-
| `@sourceregistry/node-jwt`
|
|
234
|
-
| `@sourceregistry/node-jwt/promises` | Promise
|
|
235
|
-
|
|
236
|
-
Both include full TypeScript types and JSDoc.
|
|
215
|
+
| Import | Description |
|
|
216
|
+
| ----------------------------------- | ----------- |
|
|
217
|
+
| `@sourceregistry/node-jwt` | Sync API |
|
|
218
|
+
| `@sourceregistry/node-jwt/promises` | Promise API |
|
|
237
219
|
|
|
238
220
|
---
|
|
239
221
|
|
|
240
|
-
🙌
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
- Follow existing code style
|
|
222
|
+
## 🙌 Contributing
|
|
223
|
+
|
|
224
|
+
PRs welcome!
|
|
225
|
+
Please add tests and maintain full coverage.
|
|
245
226
|
|
|
246
|
-
|
|
227
|
+
🔐 Security issues? Report responsibly: **[a.p.a.slaa@projectsource.nl](mailto:a.p.a.slaa@projectsource.nl)**
|
|
247
228
|
|
|
248
|
-
🔗
|
|
249
|
-
📦
|
|
229
|
+
🔗 GitHub: [https://github.com/SourceRegistry/node-jwt](https://github.com/SourceRegistry/node-jwt)
|
|
230
|
+
📦 npm: [https://www.npmjs.com/package/@sourceregistry/node-jwt](https://www.npmjs.com/package/@sourceregistry/node-jwt)
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";const a=require("crypto"),d={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}}}},H=Object.keys(f);function A(e){if(e.type==="secret")return"HS256";if(e.type!=="private")throw new Error("Only private or symmetric keys can be used to sign JWTs");const r=e.asymmetricKeyType,t=e.asymmetricKeyDetails;switch(r){case"rsa":return"RS256";case"rsa-pss":{const i=t?.hashAlgorithm??"sha256";switch(i){case"sha256":return"PS256";case"sha384":return"PS384";case"sha512":return"PS512";default:throw new Error(`Unsupported RSA-PSS hash algorithm: ${i}`)}}case"ec":{const i=t?.namedCurve;switch(i){case"P-256":case"prime256v1":return"ES256";case"P-384":case"secp384r1":return"ES384";case"P-521":case"secp521r1":return"ES512";case"secp256k1":return"ES256K";default:throw new Error(`Unsupported EC curve: ${i}`)}}case"ed25519":return"EdDSA";default:throw new Error(`Unsupported asymmetric key type: ${r}`)}}function D(e){if(typeof e=="object"&&"type"in e)return e;try{return a.createPrivateKey(e)}catch{const r=typeof e=="string"?Buffer.from(e,"utf8"):Buffer.isBuffer(e)?e:(()=>{throw new Error("Unsupported key type")})();return a.createSecretKey(r)}}const p=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(d.decode(t)),c=JSON.parse(d.decode(i));return{header:n,payload:c,signature:s}}catch(n){throw new Error(`Invalid JWT: malformed header or payload (${n.message})`)}},b=(e,r,t={})=>{const i=D(r),s=t.alg??A(i),n=t.typ??"JWT";if(!(s in f))throw new Error(`Unsupported algorithm: ${s}`);const c={alg:s,typ:n};t.kid&&(c.kid=t.kid);const u=d.encode(JSON.stringify(c)),S=d.encode(JSON.stringify(e)),v=`${u}.${S}`,l=f[s].sign(v,r);return`${u}.${S}.${l}`},I=(e,r,t={})=>{let i;try{i=p(e)}catch(o){return{valid:!1,error:{reason:o.message,code:"INVALID_TOKEN"}}}const{header:s,payload:n,signature:c}=i,u=s.alg;if(!(u 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(u))return{valid:!1,error:{reason:`Algorithm "${u}" 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 S=`${d.encode(JSON.stringify(s))}.${d.encode(JSON.stringify(n))}`;if(!f[u].verify(S,r,c))return{valid:!1,error:{reason:"Signature verification failed",code:"INVALID_SIGNATURE"}};const l=Math.floor(Date.now()/1e3),g=t.clockSkew??0;if(!t.ignoreExpiration&&n.exp!==void 0&&l>n.exp+g)return{valid:!1,error:{reason:"Token expired",code:"TOKEN_EXPIRED"}};if(n.nbf!==void 0&&l+g<n.nbf)return{valid:!1,error:{reason:"Token not yet valid",code:"TOKEN_NOT_ACTIVE"}};if(n.iat!==void 0&&l+g<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 o=l-n.iat;if(o>t.maxTokenAge)return{valid:!1,error:{reason:`Token age (${o}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 o=n.aud;if(o===void 0)return{valid:!1,error:{reason:'Token missing required audience claim ("aud")',code:"MISSING_AUDIENCE"}};const _=Array.isArray(t.audience)?t.audience:[t.audience],N=Array.isArray(o)?o:[o];if(!_.some(W=>N.includes(W)))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:c}},R={sign:b,verify:I,decode:p,algorithms:f};function E(e){if(!e||typeof e!="object")throw new Error("Invalid KeyObject");return e.export({format:"jwk"})}function h(e){if(!e||typeof e!="object")throw new Error("Invalid JWK");switch(e.kty){case"oct":{if(!("k"in e)||typeof e.k!="string")throw new Error('Invalid oct JWK: missing "k"');return a.createSecretKey(Buffer.from(e.k,"base64url"))}case"RSA":case"EC":case"OKP":return"d"in e&&typeof e.d=="string"?a.createPrivateKey({format:"jwk",key:e}):a.createPublicKey({format:"jwk",key:e});default:throw new Error(`Unsupported JWK key type: ${e.kty}`)}}function K(e){if(!e||typeof e!="object")throw new Error("Invalid KeyObject");const t=(e.type==="private"?a.createPublicKey(e):e).export({format:"jwk"});return delete t.d,delete t.p,delete t.q,delete t.dp,delete t.dq,delete t.qi,t}function m(e,r="sha256"){if(!e||typeof e!="object")throw new Error("Invalid JWK");let t;switch(e.kty){case"RSA":t={e:e.e,kty:e.kty,n:e.n};break;case"EC":t={crv:e.crv,kty:e.kty,x:e.x,y:e.y};break;case"OKP":t={crv:e.crv,kty:e.kty,x:e.x};break;case"oct":t={k:e.k,kty:e.kty};break;default:throw new Error(`Unsupported JWK key type: ${e.kty}`)}const i=JSON.stringify(Object.keys(t).sort().reduce((s,n)=>(s[n]=t[n],s),{}));return a.createHash(r).update(i).digest("base64url")}function T(e){if(e.x5c?.length)return a.createHash("sha1").update(Buffer.from(e.x5c[0],"base64")).digest("base64url")}const x={export:E,import:h,toPublic:K,thumbprint:m};function J(e,r){if(!e||!Array.isArray(e.keys))throw new Error("Invalid JWKS");let t;if(r&&(t=e.keys.find(i=>i.kid===r)),!t&&e.keys.length===1&&(t=e.keys[0]),!t)throw new Error("Key not found in JWKS");return h(t)}function P(e){return{keys:e.keys.map(r=>({...r,kid:r.kid??m(r),x5t:r.x5t??T(r)}))}}const O={toKeyObject:J,normalize:P};exports.AutodetectAlgorithm=A;exports.JWK=x;exports.JWKS=O;exports.JWKSToKeyObject=J;exports.JWT=R;exports.SignatureAlgorithm=f;exports.SupportedAlgorithms=H;exports.base64Url=d;exports.computeX5T=T;exports.decode=p;exports.exportJWK=E;exports.getJWKThumbprint=m;exports.importJWK=h;exports.normalizeJWKS=P;exports.sign=b;exports.toPublicJWK=K;exports.verify=I;
|
|
2
|
+
//# sourceMappingURL=index-CSRWSLal.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-CSRWSLal.cjs","sources":["../src/jwt/index.ts","../src/jwks/index.ts"],"sourcesContent":["import crypto, {\n createHmac,\n createSign,\n createVerify,\n createPrivateKey,\n createSecretKey,\n sign as cryptoSign,\n verify as cryptoVerify,\n timingSafeEqual,\n type BinaryLike,\n type KeyLike,\n type KeyObject\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/**\n * Timing-safe string comparison to prevent timing attacks\n * @param a\n * @param b\n */\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 * Autodetection of algorithm for KeyObjects\n * @param key\n * @constructor\n */\nexport function AutodetectAlgorithm(key: KeyObject): SupportedAlgorithm {\n if (key.type === 'secret') return 'HS256';\n if (key.type !== 'private') throw new Error('Only private or symmetric keys can be used to sign JWTs');\n\n const asymKeyType = key.asymmetricKeyType;\n const details = key.asymmetricKeyDetails;\n\n switch (asymKeyType) {\n case 'rsa':\n return 'RS256';\n case 'rsa-pss': {\n const hash = details?.hashAlgorithm ?? 'sha256';\n switch (hash) {\n case 'sha256':\n return 'PS256';\n case 'sha384':\n return 'PS384';\n case 'sha512':\n return 'PS512';\n default:\n throw new Error(`Unsupported RSA-PSS hash algorithm: ${hash}`);\n }\n }\n case 'ec': {\n const curve = details?.namedCurve;\n switch (curve) {\n case 'P-256':\n case 'prime256v1':\n return 'ES256';\n case 'P-384':\n case 'secp384r1':\n return 'ES384';\n case 'P-521':\n case 'secp521r1':\n return 'ES512';\n case 'secp256k1':\n return 'ES256K';\n default:\n throw new Error(`Unsupported EC curve: ${curve}`);\n }\n }\n case 'ed25519':\n return 'EdDSA';\n default:\n throw new Error(`Unsupported asymmetric key type: ${asymKeyType}`);\n }\n}\n\n/**\n * Normalize KeyLike input to a KeyObject\n * @param key\n */\nfunction toKeyObject(key: KeyLike): KeyObject {\n // Already a KeyObject (private, public, or secret)\n if (typeof key === 'object' && 'type' in key) return key as KeyObject;\n\n // Try asymmetric private key (PEM / DER / JWK)\n try {\n return createPrivateKey(key);\n } catch {\n // Fallback: symmetric key (HMAC)\n const buffer =\n typeof key === 'string'\n ? Buffer.from(key, 'utf8')\n : Buffer.isBuffer(key)\n ? key\n : (() => {\n throw new Error('Unsupported key type');\n })();\n\n return createSecretKey(buffer);\n }\n}\n\n/**\n * Decode a JWT string into its parts (without verification)\n * @param token\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 * @param payload\n * @param secret\n * @param options\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 key = toKeyObject(secret);\n const alg = options.alg ?? AutodetectAlgorithm(key); // ← fixed: use `key`\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); // ← note: pass original `secret` to sign()\n\n return `${headerEncoded}.${payloadEncoded}.${signature}`;\n};\n\n/**\n * Verify and validate a JWT\n * @param token\n * @param secret\n * @param options\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//namespace export\nexport const JWT = {\n sign,\n verify,\n decode,\n algorithms: SignatureAlgorithm\n};\n\n","import {\n createPrivateKey,\n createPublicKey,\n createSecretKey,\n createHash,\n type KeyObject\n} from 'crypto';\n\n// JWK Types\nexport type JWK =\n | RSAJWK\n | ECJWK\n | OKPJWK\n | OctJWK;\n\ninterface BaseJWK {\n kty: string;\n kid?: string;\n alg?: string;\n use?: 'sig' | 'enc';\n key_ops?: Array<'sign' | 'verify'>;\n x5c?: string[]; // X.509 cert chain\n x5t?: string; // Base64url thumbprint\n}\n\nexport interface RSAJWK extends BaseJWK {\n kty: 'RSA';\n n: string;\n e: string;\n d?: string;\n p?: string;\n q?: string;\n dp?: string;\n dq?: string;\n qi?: string;\n}\n\nexport interface ECJWK extends BaseJWK {\n kty: 'EC';\n crv: 'P-256' | 'P-384' | 'P-521' | 'secp256k1';\n x: string;\n y: string;\n d?: string;\n}\n\nexport interface OKPJWK extends BaseJWK {\n kty: 'OKP';\n crv: 'Ed25519';\n x: string;\n d?: string;\n}\n\nexport interface OctJWK extends BaseJWK {\n kty: 'oct';\n k: string;\n}\n\n/**\n * Export KeyObject to JWK\n * @param key\n */\nexport function exportJWK(key: KeyObject): JWK {\n if (!key || typeof key !== 'object') throw new Error('Invalid KeyObject');\n return key.export({format: 'jwk'}) as JWK;\n}\n\n/**\n * Import JWK to KeyObject\n * @param jwk\n */\nexport function importJWK(jwk: JWK): KeyObject {\n if (!jwk || typeof jwk !== 'object') throw new Error('Invalid JWK');\n\n switch (jwk.kty) {\n case 'oct': {\n if (!('k' in jwk) || typeof jwk.k !== 'string') {\n throw new Error('Invalid oct JWK: missing \"k\"');\n }\n\n return createSecretKey(Buffer.from(jwk.k, 'base64url'));\n }\n\n case 'RSA':\n case 'EC':\n case 'OKP': {\n // private key\n if ('d' in jwk && typeof (jwk as any).d === 'string') {\n // @ts-ignore\n return createPrivateKey({format: 'jwk', key: jwk});\n }\n\n // public key\n // @ts-ignore\n return createPublicKey({format: 'jwk', key: jwk});\n }\n\n default:\n throw new Error(`Unsupported JWK key type: ${(jwk as any).kty}`);\n }\n}\n\n/**\n * Export public-only JWK\n * @param key\n */\nexport function toPublicJWK(key: KeyObject): JWK {\n if (!key || typeof key !== 'object') {\n throw new Error('Invalid KeyObject');\n }\n\n const publicKey =\n key.type === 'private'\n ? createPublicKey(key)\n : key;\n\n const jwk = publicKey.export({format: 'jwk'}) as JWK;\n\n // Ensure private fields are not present\n delete (jwk as any).d;\n delete (jwk as any).p;\n delete (jwk as any).q;\n delete (jwk as any).dp;\n delete (jwk as any).dq;\n delete (jwk as any).qi;\n return jwk;\n}\n\n/**\n * RFC 7638 JWK thumbprint\n * @param jwk\n * @param hashAlg\n */\nexport function getJWKThumbprint(jwk: JWK, hashAlg: 'sha256' = 'sha256'): string {\n if (!jwk || typeof jwk !== 'object') {\n throw new Error('Invalid JWK');\n }\n\n let fields: Record<string, string>;\n\n switch (jwk.kty) {\n case 'RSA':\n fields = {e: jwk.e, kty: jwk.kty, n: jwk.n};\n break;\n\n case 'EC':\n fields = {crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y};\n break;\n\n case 'OKP':\n fields = {crv: jwk.crv, kty: jwk.kty, x: jwk.x};\n break;\n\n case 'oct':\n fields = {k: jwk.k, kty: jwk.kty};\n break;\n\n default:\n throw new Error(`Unsupported JWK key type: ${(jwk as any).kty}`);\n }\n\n // Lexicographically sorted JSON\n const json = JSON.stringify(\n Object.keys(fields)\n .sort()\n .reduce((acc, k) => {\n acc[k] = fields[k];\n return acc;\n }, {} as Record<string, string>)\n );\n\n return createHash(hashAlg)\n .update(json)\n .digest('base64url');\n}\n\n\n/**\n * Compute x5t (SHA-1) from first cert in x5c if not set\n * @param jwk\n */\nexport function computeX5T(jwk: JWK): string | undefined {\n if (!jwk.x5c?.length) return undefined;\n return createHash('sha1').update(Buffer.from(jwk.x5c[0], 'base64')).digest('base64url');\n}\n\nexport const JWK = {\n export: exportJWK,\n import: importJWK,\n toPublic: toPublicJWK,\n thumbprint: getJWKThumbprint,\n}\n\nexport interface JWKS {\n keys: JWK[];\n}\n\n/**\n * Convert JWKS specific key of first key to KeyObject\n * @param jwks\n * @param kid\n * @constructor\n */\nexport function JWKSToKeyObject(\n jwks: JWKS,\n kid?: string\n): KeyObject {\n if (!jwks || !Array.isArray(jwks.keys)) throw new Error('Invalid JWKS');\n\n let jwk: JWK | undefined;\n\n if (kid) jwk = jwks.keys.find(k => k.kid === kid);\n\n // Fallback: single-key JWKS\n if (!jwk && jwks.keys.length === 1) jwk = jwks.keys[0];\n\n if (!jwk) throw new Error('Key not found in JWKS');\n return importJWK(jwk);\n}\n\n/**\n * Normalize JWKS\n * @param jwks\n */\nexport function normalizeJWKS(jwks: JWKS): JWKS {\n return {\n keys: jwks.keys.map(jwk => ({\n ...jwk,\n kid: jwk.kid ?? getJWKThumbprint(jwk),\n x5t: jwk.x5t ?? computeX5T(jwk)\n }))\n };\n}\n\nexport const JWKS = {\n toKeyObject: JWKSToKeyObject,\n normalize: normalizeJWKS\n}\n"],"names":["base64Url","input","timingSafeCompare","a","b","timingSafeEqual","SignatureAlgorithm","data","secret","createHmac","signature","expected","createSign","createVerify","crypto","cryptoSign","cryptoVerify","SupportedAlgorithms","AutodetectAlgorithm","key","asymKeyType","details","hash","curve","toKeyObject","createPrivateKey","buffer","createSecretKey","decode","token","parts","headerPart","payloadPart","header","payload","err","sign","options","alg","typ","headerEncoded","payloadEncoded","signingInput","verify","decoded","now","skew","tokenAge","aud","expectedAud","tokenAud","JWT","exportJWK","importJWK","jwk","createPublicKey","toPublicJWK","getJWKThumbprint","hashAlg","fields","json","acc","k","createHash","computeX5T","JWK","JWKSToKeyObject","jwks","kid","normalizeJWKS","JWKS"],"mappings":"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"}
|