@lindorm/aegis 0.3.5 → 0.4.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.
Files changed (106) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/README.md +247 -163
  3. package/__tests__/__mocks__/cbor.ts +17 -0
  4. package/__tests__/cose-interop.test.ts +1127 -0
  5. package/__tests__/jwe-interop.test.ts +331 -0
  6. package/__tests__/jwt-interop.test.ts +183 -0
  7. package/dist/classes/Aegis.d.ts.map +1 -1
  8. package/dist/classes/Aegis.js +8 -5
  9. package/dist/classes/Aegis.js.map +1 -1
  10. package/dist/classes/CweKit.d.ts.map +1 -1
  11. package/dist/classes/CweKit.js +31 -37
  12. package/dist/classes/CweKit.js.map +1 -1
  13. package/dist/classes/CwsKit.d.ts.map +1 -1
  14. package/dist/classes/CwsKit.js +8 -3
  15. package/dist/classes/CwsKit.js.map +1 -1
  16. package/dist/classes/CwtKit.d.ts.map +1 -1
  17. package/dist/classes/CwtKit.js +10 -14
  18. package/dist/classes/CwtKit.js.map +1 -1
  19. package/dist/classes/JweKit.d.ts.map +1 -1
  20. package/dist/classes/JweKit.js +24 -47
  21. package/dist/classes/JweKit.js.map +1 -1
  22. package/dist/classes/JwsKit.d.ts.map +1 -1
  23. package/dist/classes/JwsKit.js +9 -2
  24. package/dist/classes/JwsKit.js.map +1 -1
  25. package/dist/classes/JwtKit.d.ts.map +1 -1
  26. package/dist/classes/JwtKit.js +10 -9
  27. package/dist/classes/JwtKit.js.map +1 -1
  28. package/dist/classes/SignatureKit.d.ts.map +1 -1
  29. package/dist/classes/SignatureKit.js +2 -1
  30. package/dist/classes/SignatureKit.js.map +1 -1
  31. package/dist/constants/private/cose.d.ts +0 -1
  32. package/dist/constants/private/cose.d.ts.map +1 -1
  33. package/dist/constants/private/cose.js +5 -23
  34. package/dist/constants/private/cose.js.map +1 -1
  35. package/dist/types/cose-target.d.ts +2 -0
  36. package/dist/types/cose-target.d.ts.map +1 -0
  37. package/dist/types/{operators.js → cose-target.js} +1 -1
  38. package/dist/types/cose-target.js.map +1 -0
  39. package/dist/types/cwe/cwe-decode.d.ts +6 -2
  40. package/dist/types/cwe/cwe-decode.d.ts.map +1 -1
  41. package/dist/types/cwe/cwe-decrypt.d.ts +2 -2
  42. package/dist/types/cwe/cwe-decrypt.d.ts.map +1 -1
  43. package/dist/types/cwe/cwe-encrypt.d.ts +2 -0
  44. package/dist/types/cwe/cwe-encrypt.d.ts.map +1 -1
  45. package/dist/types/cws/cws-sign.d.ts +2 -0
  46. package/dist/types/cws/cws-sign.d.ts.map +1 -1
  47. package/dist/types/cwt/cwt-sign.d.ts +4 -1
  48. package/dist/types/cwt/cwt-sign.d.ts.map +1 -1
  49. package/dist/types/header.d.ts +6 -10
  50. package/dist/types/header.d.ts.map +1 -1
  51. package/dist/types/index.d.ts +1 -1
  52. package/dist/types/index.d.ts.map +1 -1
  53. package/dist/types/index.js +1 -1
  54. package/dist/types/index.js.map +1 -1
  55. package/dist/types/jwt/jwt-validate.d.ts +21 -21
  56. package/dist/types/jwt/jwt-validate.d.ts.map +1 -1
  57. package/dist/types/jwt/jwt-verify.d.ts +21 -21
  58. package/dist/types/jwt/jwt-verify.d.ts.map +1 -1
  59. package/dist/utils/private/auth-tag-length.js.map +1 -1
  60. package/dist/utils/private/cose/claims.d.ts +3 -3
  61. package/dist/utils/private/cose/claims.d.ts.map +1 -1
  62. package/dist/utils/private/cose/claims.js +27 -5
  63. package/dist/utils/private/cose/claims.js.map +1 -1
  64. package/dist/utils/private/cose/header.d.ts +3 -3
  65. package/dist/utils/private/cose/header.d.ts.map +1 -1
  66. package/dist/utils/private/cose/header.js +19 -26
  67. package/dist/utils/private/cose/header.js.map +1 -1
  68. package/dist/utils/private/cose/key.d.ts +1 -1
  69. package/dist/utils/private/cose/key.d.ts.map +1 -1
  70. package/dist/utils/private/cose/key.js +16 -12
  71. package/dist/utils/private/cose/key.js.map +1 -1
  72. package/dist/utils/private/cose-sign-token.d.ts +1 -2
  73. package/dist/utils/private/cose-sign-token.d.ts.map +1 -1
  74. package/dist/utils/private/cose-sign-token.js.map +1 -1
  75. package/dist/utils/private/index.d.ts +0 -1
  76. package/dist/utils/private/index.d.ts.map +1 -1
  77. package/dist/utils/private/index.js +0 -1
  78. package/dist/utils/private/index.js.map +1 -1
  79. package/dist/utils/private/jose-header.d.ts.map +1 -1
  80. package/dist/utils/private/jose-header.js +12 -17
  81. package/dist/utils/private/jose-header.js.map +1 -1
  82. package/dist/utils/private/jwt-validate.d.ts +3 -3
  83. package/dist/utils/private/jwt-validate.d.ts.map +1 -1
  84. package/dist/utils/private/jwt-validate.js +9 -9
  85. package/dist/utils/private/jwt-validate.js.map +1 -1
  86. package/dist/utils/private/jwt-verify.d.ts +3 -3
  87. package/dist/utils/private/jwt-verify.d.ts.map +1 -1
  88. package/dist/utils/private/jwt-verify.js +14 -14
  89. package/dist/utils/private/jwt-verify.js.map +1 -1
  90. package/dist/utils/private/token-header.d.ts.map +1 -1
  91. package/dist/utils/private/token-header.js +2 -10
  92. package/dist/utils/private/token-header.js.map +1 -1
  93. package/dist/utils/private/validate.d.ts +2 -3
  94. package/dist/utils/private/validate.d.ts.map +1 -1
  95. package/dist/utils/private/validate.js +9 -10
  96. package/dist/utils/private/validate.js.map +1 -1
  97. package/jest.config.interop.mjs +27 -0
  98. package/package.json +24 -24
  99. package/tsconfig.interop.json +9 -0
  100. package/dist/types/operators.d.ts +0 -27
  101. package/dist/types/operators.d.ts.map +0 -1
  102. package/dist/types/operators.js.map +0 -1
  103. package/dist/utils/private/validate-value.d.ts +0 -3
  104. package/dist/utils/private/validate-value.d.ts.map +0 -1
  105. package/dist/utils/private/validate-value.js +0 -91
  106. package/dist/utils/private/validate-value.js.map +0 -1
package/CHANGELOG.md CHANGED
@@ -3,6 +3,31 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [0.4.0](https://github.com/lindorm-io/monorepo/compare/@lindorm/aegis@0.3.6...@lindorm/aegis@0.4.0) (2026-02-17)
7
+
8
+ ### Bug Fixes
9
+
10
+ - **aegis:** align header parsing types with AES decryption record types ([8d6539d](https://github.com/lindorm-io/monorepo/commit/8d6539d41657343edce4c94c884fe592c9bb12e6))
11
+ - **aegis:** relax algorithm validation in header decoding ([fbc6edc](https://github.com/lindorm-io/monorepo/commit/fbc6edc003849963827c483ff2d995cd5b66eada))
12
+ - **aegis:** relax typ validation and fix kryptosSig algorithm bug ([cb1bb60](https://github.com/lindorm-io/monorepo/commit/cb1bb601e2004de4b0a6454dd60a35be7770f59c))
13
+ - **aegis:** remove hkdfSalt references after aes package refactor ([30c008a](https://github.com/lindorm-io/monorepo/commit/30c008a99a364928ed83fbb7ee6b496691646f80))
14
+ - **aegis:** remove jwksUri from COSE sign/encrypt headers ([2c47fd4](https://github.com/lindorm-io/monorepo/commit/2c47fd43297db43e8f6b98df4b25ee93e93415af))
15
+ - **aegis:** restructure CweKit header layout per RFC 9052 ([43f2616](https://github.com/lindorm-io/monorepo/commit/43f2616b34de529e968f75714a2222ed4d02a509))
16
+ - **aegis:** rFC 7515 crit compliance and base64url header encoding ([f3fa30b](https://github.com/lindorm-io/monorepo/commit/f3fa30b89f10518efa86ad69577e1d1c35faf030))
17
+ - **aegis:** use Map-based COSE encoding for RFC 9052 integer labels ([e2eb229](https://github.com/lindorm-io/monorepo/commit/e2eb229b053c9c91ba8b4b43d8ad9e1731ec53b4))
18
+ - **lint:** add missing eslint-config-prettier and fix prettier formatting ([6899e39](https://github.com/lindorm-io/monorepo/commit/6899e39ad7700e373173b0a61b429b5536c13934))
19
+
20
+ ### Features
21
+
22
+ - **aegis:** add COSE target mode for internal/external encoding ([0be6874](https://github.com/lindorm-io/monorepo/commit/0be687457cea0266cefdff8fc504b05175aa8bbf))
23
+ - **aegis:** integrate prepareEncryption for JWE AAD support ([0b5a607](https://github.com/lindorm-io/monorepo/commit/0b5a60749b935068a02c6ae9fa1a637e0bfa8764))
24
+ - **aegis:** narrow AmphoraQuery type by operation ([e908b40](https://github.com/lindorm-io/monorepo/commit/e908b405f5269aaa864f2da5b19879f9d999e485))
25
+ - **aegis:** support custom COSE claim labels (>= 900) in CWT payloads ([a5f30c0](https://github.com/lindorm-io/monorepo/commit/a5f30c09d6ca21dc029a6d2a601ff3cf35b8dff4))
26
+
27
+ ## [0.3.6](https://github.com/lindorm-io/monorepo/compare/@lindorm/aegis@0.3.5...@lindorm/aegis@0.3.6) (2025-09-18)
28
+
29
+ **Note:** Version bump only for package @lindorm/aegis
30
+
6
31
  ## [0.3.5](https://github.com/lindorm-io/monorepo/compare/@lindorm/aegis@0.3.4...@lindorm/aegis@0.3.5) (2025-07-19)
7
32
 
8
33
  **Note:** Version bump only for package @lindorm/aegis
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @lindorm/aegis
2
2
 
3
- A comprehensive TypeScript library for JWT, JWE, JWS, CBOR Web Token (CWT), COSE Sign (CWS), and COSE Encrypt (CWE) operations with cryptographic key management integration.
3
+ Token operations for JWT, JWE, JWS, CWT (CBOR Web Token), CWS (COSE Sign1), and CWE (COSE Encrypt).
4
4
 
5
5
  ## Installation
6
6
 
@@ -8,254 +8,338 @@ A comprehensive TypeScript library for JWT, JWE, JWS, CBOR Web Token (CWT), COSE
8
8
  npm install @lindorm/aegis
9
9
  ```
10
10
 
11
- ## Features
11
+ ## Overview
12
12
 
13
- - **JWT Operations**: Sign and verify JSON Web Tokens
14
- - **JWE Operations**: Encrypt and decrypt JSON Web Encryption
15
- - **JWS Operations**: Sign and verify JSON Web Signatures
16
- - **CWT Operations**: Sign and verify CBOR Web Tokens
17
- - **CWS Operations**: Sign and verify COSE Sign messages
18
- - **CWE Operations**: Encrypt and decrypt COSE Encrypt messages
19
- - **AES Operations**: AES encryption and decryption with multiple output formats
20
- - **Static Token Analysis**: Decode, parse, and validate tokens without verification
21
- - **Universal Verification**: Automatically detect and verify any supported token type
13
+ Aegis provides two usage patterns:
22
14
 
23
- ## Basic Usage
15
+ - **Aegis class** — async wrapper that resolves keys from an `IAmphora` key store before delegating to Kit classes.
16
+ - **Kit classes** (`JwtKit`, `CwtKit`, `CwsKit`, etc.) — synchronous, single-key operations. You supply an `IKryptos` key directly.
24
17
 
25
- ### Setup
18
+ The Aegis class methods are **async** because they perform key lookups. All Kit class methods are **synchronous**.
26
19
 
27
- ```typescript
28
- import { Aegis } from '@lindorm/aegis';
29
- import { Amphora } from '@lindorm/amphora';
30
- import { Logger } from '@lindorm/logger';
20
+ ## Aegis Class
21
+
22
+ Async wrapper that resolves keys from an `IAmphora` key store. All operations are async.
31
23
 
32
- const logger = new Logger();
33
- const amphora = new Amphora({ domain: 'https://example.com', logger });
24
+ ```typescript
25
+ import { Aegis } from "@lindorm/aegis";
34
26
 
35
27
  const aegis = new Aegis({
36
28
  amphora,
37
29
  logger,
38
- issuer: 'https://example.com', // Optional: defaults to amphora.domain
39
- clockTolerance: 30000, // Optional: 30 seconds tolerance for time-based claims
30
+ issuer: "https://example.com",
31
+ clockTolerance: 30000, // ms, optional
32
+ encryption: "A256GCM", // optional, default "A256GCM"
33
+ encAlgorithm: "ECDH-ES", // optional, default encryption algorithm
34
+ sigAlgorithm: "ES256", // optional, default signing algorithm
40
35
  });
41
-
42
- // Setup and add keys to amphora
43
- await amphora.setup();
44
- // amphora.add(kryptosKey);
45
36
  ```
46
37
 
47
- ### JWT Operations
38
+ ### Namespaced operations
48
39
 
49
40
  ```typescript
50
- // Sign a JWT
51
- const signedJwt = await aegis.jwt.sign({
52
- expires: '1h',
53
- subject: 'user123',
54
- tokenType: 'access_token',
55
- claims: { name: 'John Doe', admin: true },
56
- audience: ['https://api.example.com'],
57
- scope: ['read', 'write']
41
+ // JWT
42
+ const signed = await aegis.jwt.sign({
43
+ expires: "1h",
44
+ subject: "u1",
45
+ tokenType: "access_token",
58
46
  });
47
+ const parsed = await aegis.jwt.verify(signed.token);
59
48
 
60
- // Verify a JWT
61
- const parsedJwt = await aegis.jwt.verify(signedJwt.token, {
62
- audience: 'https://api.example.com',
63
- scope: ['read']
49
+ // CWT
50
+ const cwt = await aegis.cwt.sign({
51
+ expires: "1h",
52
+ subject: "u1",
53
+ tokenType: "access_token",
64
54
  });
65
- ```
55
+ const cwtParsed = await aegis.cwt.verify(cwt.token);
66
56
 
67
- ### JWE Operations
57
+ // JWS / CWS — sign and verify arbitrary data
58
+ const jws = await aegis.jws.sign("data");
59
+ const cws = await aegis.cws.sign("data");
68
60
 
69
- ```typescript
70
- // Encrypt data with JWE
71
- const encryptedJwe = await aegis.jwe.encrypt('sensitive data', {
72
- objectId: 'message-123'
73
- });
61
+ // JWE / CWE — encrypt and decrypt
62
+ const jwe = await aegis.jwe.encrypt("secret");
63
+ const cwe = await aegis.cwe.encrypt("secret");
74
64
 
75
- // Decrypt JWE
76
- const decryptedJwe = await aegis.jwe.decrypt(encryptedJwe.token);
77
- console.log(decryptedJwe.payload); // 'sensitive data'
65
+ // AES — returns base64 encoded string by default
66
+ const encoded = await aegis.aes.encrypt("data");
67
+ const record = await aegis.aes.encrypt("data", "record");
68
+ const serialised = await aegis.aes.encrypt("data", "serialised");
69
+ const decrypted = await aegis.aes.decrypt(encoded);
78
70
  ```
79
71
 
80
- ### JWS Operations
72
+ ### Universal verification
73
+
74
+ Automatically detects token type and verifies/decrypts accordingly.
81
75
 
82
76
  ```typescript
83
- // Sign arbitrary data with JWS
84
- const signedJws = await aegis.jws.sign('Hello World', {
85
- objectId: 'message-456'
77
+ const result = await aegis.verify(anyToken, {
78
+ audience: "https://api.example.com",
86
79
  });
80
+ // Works with JWT, JWE, JWS, CWT, CWE, or CWS
81
+ // JWE/CWE tokens are decrypted, then their inner payload is verified
82
+ ```
83
+
84
+ ### Static methods
87
85
 
88
- // Verify JWS
89
- const parsedJws = await aegis.jws.verify(signedJws.token);
90
- console.log(parsedJws.payload); // 'Hello World'
86
+ No key or amphora required.
87
+
88
+ ```typescript
89
+ Aegis.isJwt(token);
90
+ Aegis.isCwt(token);
91
+ Aegis.isJws(token);
92
+ Aegis.isCws(token);
93
+ Aegis.isJwe(token);
94
+ Aegis.isCwe(token);
95
+
96
+ Aegis.header(token); // TokenHeaderClaims (JOSE tokens only)
97
+ Aegis.decode(token); // auto-detect and decode without verification
98
+ Aegis.parse(token); // auto-detect, decode, and validate structure
91
99
  ```
92
100
 
93
- ### CBOR Web Token (CWT) Operations
101
+ ## Kit Classes
102
+
103
+ ### JwtKit
104
+
105
+ Signs and verifies JSON Web Tokens.
94
106
 
95
107
  ```typescript
96
- // Sign a CWT (CBOR Web Token)
97
- const signedCwt = await aegis.cwt.sign({
98
- expires: '2h',
99
- subject: 'user123',
100
- tokenType: 'access_token',
101
- audience: ['api.example.com']
108
+ import { JwtKit } from "@lindorm/aegis";
109
+
110
+ const kit = new JwtKit({ issuer: "https://example.com", logger, kryptos });
111
+
112
+ // Sign — returns { token, expiresAt, expiresIn, expiresOn, objectId, tokenId }
113
+ const signed = kit.sign({
114
+ expires: "1h",
115
+ subject: "user-123",
116
+ tokenType: "access_token",
117
+ audience: ["https://api.example.com"],
118
+ claims: { role: "admin" },
119
+ scope: ["read", "write"],
120
+ });
121
+
122
+ // Verify — returns { decoded, header, payload, token }
123
+ const parsed = kit.verify(signed.token, {
124
+ audience: "https://api.example.com",
125
+ scope: ["read"],
102
126
  });
103
127
 
104
- // Verify CWT
105
- const parsedCwt = await aegis.cwt.verify(signedCwt.token);
128
+ // Static methods (no key required)
129
+ JwtKit.isJwt(token); // boolean
130
+ JwtKit.decode(token); // { header, payload, signature }
131
+ JwtKit.parse(token); // { decoded, header, payload, token }
132
+ JwtKit.validate(payload, options); // throws on mismatch
106
133
  ```
107
134
 
108
- ### COSE Operations
135
+ ### CwtKit
136
+
137
+ Signs and verifies CBOR Web Tokens (RFC 8392). Uses COSE Sign1 structure with CBOR-encoded payloads and integer claim labels.
109
138
 
110
139
  ```typescript
111
- // COSE Encrypt (CWE)
112
- const encryptedCwe = await aegis.cwe.encrypt('secret message', {
113
- objectId: 'message-123'
114
- });
140
+ import { CwtKit } from "@lindorm/aegis";
141
+
142
+ const kit = new CwtKit({ issuer: "https://example.com", logger, kryptos });
115
143
 
116
- const decryptedCwe = await aegis.cwe.decrypt(encryptedCwe.token);
117
- console.log(decryptedCwe.payload); // 'secret message'
144
+ // Sign returns { buffer, token, expiresAt, expiresIn, expiresOn, objectId, tokenId }
145
+ const signed = kit.sign({
146
+ expires: "1h",
147
+ subject: "user-123",
148
+ tokenType: "access_token",
149
+ claims: { 900: "custom-value", 901: 42 }, // integer labels >= 900
150
+ });
118
151
 
119
- // COSE Sign (CWS)
120
- const signedCws = await aegis.cws.sign('important info', {
121
- objectId: 'message-789'
152
+ // Verify accepts Buffer or base64url string
153
+ const parsed = kit.verify(signed.token, {
154
+ tokenType: "access_token",
122
155
  });
123
- const parsedCws = await aegis.cws.verify(signedCws.token);
124
- console.log(parsedCws.payload); // 'important info'
156
+
157
+ // Static methods
158
+ CwtKit.isCwt(token);
159
+ CwtKit.decode(token);
160
+ CwtKit.parse(token);
161
+ CwtKit.validate(payload, options);
125
162
  ```
126
163
 
127
- ### AES Operations
164
+ **COSE target modes:** Pass `{ target: "external" }` to sign options to emit string keys for proprietary labels instead of integer CBOR labels. Standard RFC claims (iss, sub, exp, etc.) always use integer labels regardless of target.
165
+
166
+ **Custom claim labels:** Numeric keys >= 900 in the `claims` object are encoded as compact integer CBOR labels. Keys below 900 are rejected to prevent collision with IANA-assigned (1-255) and Lindorm-reserved (400-599) ranges.
167
+
168
+ ### CwsKit
169
+
170
+ Signs and verifies arbitrary data using COSE Sign1 (RFC 9052).
128
171
 
129
172
  ```typescript
130
- // AES encryption with different output formats
131
- const encoded = await aegis.aes.encrypt('data'); // Returns base64 encoded string
132
- const record = await aegis.aes.encrypt('data', 'record'); // Returns AesEncryptionRecord
133
- const serialised = await aegis.aes.encrypt('data', 'serialised'); // Returns SerialisedAesEncryption
173
+ import { CwsKit } from "@lindorm/aegis";
134
174
 
135
- // AES decryption (accepts any format)
136
- const decrypted = await aegis.aes.decrypt(encoded);
175
+ const kit = new CwsKit({ logger, kryptos });
176
+
177
+ // Sign string or Buffer — returns { buffer, objectId, token }
178
+ const signed = kit.sign("hello world", {
179
+ objectId: "msg-001",
180
+ target: "internal", // or "external"
181
+ });
182
+
183
+ // Verify — returns { decoded, header, payload, token }
184
+ const parsed = kit.verify(signed.token);
185
+ // parsed.payload === "hello world"
186
+
187
+ // Static methods
188
+ CwsKit.isCws(token);
189
+ CwsKit.decode(token);
190
+ CwsKit.parse(token);
137
191
  ```
138
192
 
139
- ### Universal Token Verification
193
+ ### CweKit
194
+
195
+ Encrypts and decrypts data using COSE Encrypt (RFC 9052).
140
196
 
141
197
  ```typescript
142
- // Automatically detect and verify any supported token type
143
- const result = await aegis.verify(anyTokenString, {
144
- // Optional verification options (same as JWT/CWT verify options)
145
- audience: 'https://api.example.com'
198
+ import { CweKit } from "@lindorm/aegis";
199
+
200
+ const kit = new CweKit({ logger, kryptos, encryption: "A256GCM" });
201
+
202
+ // Encrypt string or Buffer — returns { buffer, token }
203
+ const encrypted = kit.encrypt("secret data", {
204
+ objectId: "msg-002",
205
+ target: "internal",
146
206
  });
147
207
 
148
- // Works with JWT, JWE, JWS, CWT, CWE, or CWS tokens
149
- // JWE and CWE are automatically decrypted and their inner payload is verified
208
+ // Decrypt returns { decoded, header, payload, token }
209
+ const decrypted = kit.decrypt(encrypted.token);
210
+ // decrypted.payload === "secret data"
211
+
212
+ // Static methods
213
+ CweKit.isCwe(token);
214
+ CweKit.decode(token);
150
215
  ```
151
216
 
152
- ## Static Methods
217
+ ### JwsKit
153
218
 
154
- Aegis provides static methods for token analysis without requiring cryptographic verification:
219
+ Signs and verifies arbitrary data using JSON Web Signatures.
155
220
 
156
221
  ```typescript
157
- // Check token type
158
- const isJwt = Aegis.isJwt(token);
159
- const isJwe = Aegis.isJwe(token);
160
- const isCwt = Aegis.isCwt(token);
222
+ import { JwsKit } from "@lindorm/aegis";
223
+
224
+ const kit = new JwsKit({ logger, kryptos });
161
225
 
162
- // Decode tokens (header + payload, no verification)
163
- const decoded = Aegis.decode(token);
226
+ // Sign string or Buffer — returns { objectId, token }
227
+ const signed = kit.sign("hello world", { objectId: "msg-003" });
164
228
 
165
- // Parse tokens (decode + basic validation, no signature verification)
166
- const parsed = Aegis.parse(token);
229
+ // Verify returns { decoded, header, payload, token }
230
+ const parsed = kit.verify(signed.token);
167
231
 
168
- // Extract header information
169
- const header = Aegis.header(token);
232
+ // Static methods
233
+ JwsKit.isJws(token);
234
+ JwsKit.decode(token);
235
+ JwsKit.parse(token);
170
236
  ```
171
237
 
172
- ## Configuration Options
238
+ ### JweKit
173
239
 
174
- ### AegisOptions
240
+ Encrypts and decrypts data using JSON Web Encryption.
175
241
 
176
242
  ```typescript
177
- interface AegisOptions {
178
- amphora: IAmphora; // Key storage and management
179
- logger: ILogger; // Logger instance
180
- issuer?: string; // Token issuer (defaults to amphora.domain)
181
- clockTolerance?: number; // Time tolerance in milliseconds (default: 0)
182
- encAlgorithm?: KryptosEncAlgorithm; // Default encryption algorithm
183
- encryption?: KryptosEncryption; // Default encryption method (default: 'A256GCM')
184
- sigAlgorithm?: KryptosSigAlgorithm; // Default signing algorithm
185
- }
243
+ import { JweKit } from "@lindorm/aegis";
244
+
245
+ const kit = new JweKit({ logger, kryptos, encryption: "A256GCM" });
246
+
247
+ // Encrypt string returns { token }
248
+ const encrypted = kit.encrypt("secret data", { objectId: "msg-004" });
249
+
250
+ // Decrypt returns { decoded, header, payload, token }
251
+ const decrypted = kit.decrypt(encrypted.token);
252
+
253
+ // Static methods
254
+ JweKit.isJwe(token);
255
+ JweKit.decode(token);
186
256
  ```
187
257
 
188
- ### Signing Options
258
+ ### SignatureKit
259
+
260
+ Low-level signature operations over raw data.
189
261
 
190
262
  ```typescript
191
- interface SignJwtContent {
192
- expires: string; // Required: Expiration time ('1h', '30m', etc.)
193
- subject: string; // Required: Token subject
194
- tokenType: string; // Required: Type of token
195
- audience?: string[]; // Token audiences
196
- scope?: string[]; // OAuth scopes
197
- claims?: Record<string, any>; // Additional claims
198
- permissions?: string[]; // User permissions
199
- roles?: string[]; // User roles
200
- // ... many other optional fields
201
- }
263
+ import { SignatureKit } from "@lindorm/aegis";
202
264
 
203
- interface SignJwtOptions {
204
- objectId?: string; // Object identifier
205
- tokenId?: string; // Token identifier
206
- issuedAt?: Date; // Issue time (defaults to now)
207
- // ... other header options
208
- }
265
+ const kit = new SignatureKit({ kryptos });
266
+
267
+ const signature = kit.sign(data); // Buffer
268
+ const valid = kit.verify(data, signature); // boolean
269
+ kit.assert(data, signature); // throws if invalid
270
+ kit.format(signature); // string
209
271
  ```
210
272
 
211
- ### Verification Options
273
+ ## Sign Content
274
+
275
+ The `SignJwtContent` / `SignCwtContent` types share the same shape:
212
276
 
213
277
  ```typescript
214
- interface VerifyJwtOptions {
215
- audience?: string | string[] | Operators; // Required audience(s)
216
- scope?: string | string[] | Operators; // Required scope(s)
217
- subject?: string | string[] | Operators; // Expected subject(s)
218
- issuer?: string | Operators; // Expected issuer
219
- tokenType?: string | Operators; // Expected token type
220
- clientId?: string | string[] | Operators; // Expected client ID
221
- permissions?: string | string[] | Operators; // Required permissions
222
- roles?: string | string[] | Operators; // Required roles
223
- // ... many other optional verification fields with Operators support
278
+ {
279
+ // Required
280
+ expires: string | Date; // "1h", "30m", Date, etc.
281
+ subject: string;
282
+ tokenType: string;
283
+
284
+ // Optional
285
+ audience?: string[];
286
+ claims?: Record<string, any>; // custom claims (CWT supports integer keys >= 900)
287
+ scope?: string[];
288
+ permissions?: string[];
289
+ roles?: string[];
290
+ clientId?: string;
291
+ grantType?: string;
292
+ tenantId?: string;
293
+ sessionId?: string;
294
+ nonce?: string;
295
+ notBefore?: Date;
296
+ authTime?: Date;
297
+ authContextClass?: string;
298
+ authFactor?: string;
299
+ authMethods?: string[];
300
+ authorizedParty?: string;
301
+ adjustedAccessLevel?: number;
302
+ levelOfAssurance?: number;
303
+ sessionHint?: string;
304
+ subjectHint?: string;
224
305
  }
225
306
  ```
226
307
 
227
- ## Error Handling
308
+ ## Verify Options
228
309
 
229
- The package provides specific error types for different scenarios:
310
+ All fields are optional and support `PredicateOperator` for flexible matching:
230
311
 
231
312
  ```typescript
232
- import {
233
- AegisError,
313
+ kit.verify(token, {
314
+ audience: "https://api.example.com", // exact match
315
+ scope: ["read", "write"], // array contains
316
+ tokenType: { $eq: "access_token" }, // predicate operator
317
+ subject: { $in: ["user-1", "user-2"] }, // set membership
318
+ levelOfAssurance: { $gte: 2 }, // numeric comparison
319
+ });
320
+ ```
321
+
322
+ ## Errors
323
+
324
+ ```typescript
325
+ import {
326
+ AegisError, // base error
234
327
  JwtError,
235
- JweError,
236
328
  JwsError,
329
+ JweError,
237
330
  CwtError,
331
+ CoseSignError,
238
332
  CoseEncryptError,
239
- CoseSignError
240
- } from '@lindorm/aegis';
241
-
242
- try {
243
- const result = await aegis.jwt.verify(token);
244
- } catch (error) {
245
- if (error instanceof JwtError) {
246
- console.log('JWT-specific error:', error.message);
247
- } else if (error instanceof AegisError) {
248
- console.log('General Aegis error:', error.message);
249
- }
250
- }
333
+ } from "@lindorm/aegis";
251
334
  ```
252
335
 
253
- ## Key Management Integration
336
+ ## Testing
254
337
 
255
- Aegis integrates with `@lindorm/amphora` for cryptographic key management and `@lindorm/kryptos` for key operations. Keys must be properly configured in the amphora instance with appropriate purposes and operations:
338
+ ```typescript
339
+ import { createMockAegis } from "@lindorm/aegis";
256
340
 
257
- - **Encryption keys**: Purpose `enc`, operations `['encrypt', 'deriveKey', 'wrapKey', 'decrypt', 'unwrapKey']`
258
- - **Signing keys**: Purpose `sig`, operations `['sign', 'verify']`
341
+ const aegis = createMockAegis(); // fully mocked IAegis with jest.fn() stubs
342
+ ```
259
343
 
260
344
  ## License
261
345
 
@@ -0,0 +1,17 @@
1
+ // ESM bridge for the cbor package (which is CJS-only).
2
+ // Jest ESM mode cannot resolve named exports from CJS modules,
3
+ // so we load cbor via createRequire and re-export its members.
4
+ //
5
+ // We require the cbor entry point by absolute file path to avoid
6
+ // the moduleNameMapper (which maps "^cbor$" to this very file).
7
+
8
+ import { createRequire } from "module";
9
+
10
+ const require = createRequire(import.meta.url);
11
+ const cbor = require("/Users/jonn/Projects/lindorm-monorepo/node_modules/cbor/lib/cbor.js");
12
+
13
+ export const encode = cbor.encode;
14
+ export const decode = cbor.decode;
15
+ export const decodeFirst = cbor.decodeFirst;
16
+ export const Encoder = cbor.Encoder;
17
+ export const Decoder = cbor.Decoder;