Skip to content

Commit d06a916

Browse files
feat: implement crypto hardening and bump deps (#44)
TypeScript: - Add ES512SignConfig interface and createES512SignConfig() factory for ECDSA P-521 signing via the explicit API (closes #32) - Add ES256/ES384/ES512 to all asymmetric algorithm whitelists in verify.ts - Add JWT_JWKS_URL_NAME indirection to getJwksUrl() and envMode() (closes #33) - Add --alg flag to keygen CLI (EdDSA|ES256|ES384|ES512) and --dotenv output (closes #35) - Widen JwtHeader.alg from AlgType to string (external tokens have arbitrary alg) - Export createES512SignConfig and ES512SignConfig from index.ts Python: - Raise HS512 minimum secret from 32 to 64 bytes to match TypeScript - Add mode conflict detection in env.mode() — raises RuntimeError when both JWT_SECRET and asymmetric keys are configured - Widen JwtHeader.alg from AlgType to str (parity with TypeScript) Written-by: Chris Lyons
1 parent 28d7400 commit d06a916

119 files changed

Lines changed: 8189 additions & 4189 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/dependency-review.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@ jobs:
2222
with:
2323
fail-on-severity: moderate
2424
comment-summary-in-pr: always
25-
# Allow LGPL (more permissive than GPL)
26-
allow-licenses: MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, 0BSD, Unlicense, LGPL-2.1, LGPL-3.0, MPL-2.0, BlueOak-1.0.0
25+
# SPDX allowlist for dependencies currently in this repo's lockfile.
26+
# Keep this explicit so license policy changes are intentional in PRs.
27+
allow-licenses: MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, 0BSD, Unlicense, BlueOak-1.0.0, MPL-2.0, Zlib, CC0-1.0, Python-2.0, LGPL-2.0-only, LGPL-2.1, LGPL-2.1-only, LGPL-3.0, LGPL-3.0-only, LGPL-3.0-or-later

ENHANCEMENT_JWKS_HTTP_feedback.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ I’ll call out where I think you’re solid, and then a few small polish / hard
1515
- **HS512 secret strength:** 64-byte minimum with explicit enforcement.
1616
- **Single-mode requirement:** config error if HS + asym are both set.
1717

18-
From a design perspective, this is _much_ safer than the majority of roll your own JWT setups in the wild.
18+
From a design perspective, this is _much_ safer than the majority of "roll your own JWT" setups in the wild.
1919

2020
---
2121

@@ -50,9 +50,9 @@ Narrower is always safer.
5050

5151
---
5252

53-
### 2. Make the mode determined by config super explicit
53+
### 2. Make the "mode determined by config" super explicit
5454

55-
You describe it correctly, but I’d tighten the language so nobody later simplifies it back to trusting `alg`:
55+
You describe it correctly, but I’d tighten the language so nobody later "simplifies" it back to trusting `alg`:
5656

5757
> **Mode selection**
5858
>
@@ -73,7 +73,7 @@ That’s great. I’d add one short line:
7373

7474
> When importing JWKs, the expected algorithm (`'EdDSA'`, `'RS256'`, etc.) is provided explicitly, so keys cannot be repurposed for other algorithms even within the same key family.
7575
76-
That signals that you’re not just whitelisting any RS\*, you’re actually pinning at import time too.
76+
That signals that you’re not just whitelisting "any RS\*", you’re actually pinning at import time too.
7777

7878
---
7979

@@ -83,14 +83,14 @@ Returning `null` to callers is fine, but I’d explicitly say:
8383

8484
> Internally, verification failures are **logged with structured metadata** (issuer, kid, reason category) and counted in metrics. Externally, all failures are returned as `null` to avoid leaking details.
8585
86-
Otherwise someone might over-interpret fail-silent as we don’t log anything, which would be painful in prod.
86+
Otherwise someone might over-interpret "fail-silent" as "we don’t log anything," which would be painful in prod.
8787

8888
---
8989

9090
### 5. A couple of small wording / clarity tweaks
9191

92-
- You sometimes say **decrypt key** – for JWT as you’re using it, it’s **sign/verify**, not encrypt/decrypt. I’d keep wording to signing key / verification key to avoid confusion with JWE.
93-
- In Security Checklist, maybe add:
92+
- You sometimes say **"decrypt key"** – for JWT as you’re using it, it’s **sign/verify**, not encrypt/decrypt. I’d keep wording to "signing key" / "verification key" to avoid confusion with JWE.
93+
- In "Security Checklist," maybe add:
9494
- `[ ] JWT_AUD is specific per service (no wildcard audiences)` – avoids token reuse between services.
9595

9696
---
@@ -107,4 +107,4 @@ From a security-model standpoint, this looks **strong and well-documented**:
107107
- EdDSA with JWKS + optional thumbprint pinning
108108
- Reasonable claim validation (`iss`, `aud`, `exp`, `nbf`, `iat`)
109109

110-
If you clean up the minor consistency bits (RSA vs not, decrypt wording, explicit mention of logging), I’d feel very comfortable shipping this as the public here’s why you can trust our JWT handling story for flarelette.
110+
If you clean up the minor consistency bits (RSA vs not, "decrypt" wording, explicit mention of logging), I’d feel very comfortable shipping this as the public "here’s why you can trust our JWT handling" story for flarelette.

IMPLEMENTATION_SUMMARY.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ Added exports for all new explicit API functions and types.
104104

105105
### 4. Documentation
106106

107-
**New Guide:** `docs/explicit-config.md`
107+
**New Guide:** `docs/user-guide/explicit-config.md`
108108

109109
- Complete API reference
110110
- Use case examples
@@ -257,7 +257,7 @@ export async function mintToken(c: Context) {
257257

258258
-**Added:** `packages/flarelette-jwt-ts/src/explicit.ts` (489 lines)
259259
-**Added:** `packages/flarelette-jwt-ts/tests/explicit.test.ts` (470 lines)
260-
-**Added:** `docs/explicit-config.md` (complete guide)
260+
-**Added:** `docs/user-guide/explicit-config.md` (complete guide)
261261
-**Added:** `examples/explicit-config-example.ts` (example code)
262262
- 📝 **Updated:** `packages/flarelette-jwt-ts/src/index.ts` (added exports)
263263
- 📝 **Updated:** `README.md` (added new API section)

README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
**Environment-driven JWT authentication for Cloudflare Workers. Like Starlette, but for the edge.**
2020

21-
Cross-language JWT toolkit (TypeScript + Python) with identical APIs. Automatically selects HS512 or EdDSA based on environment configuration, loads secrets via Cloudflare bindings, and works across Workers, Node.js, and Python runtimes.
21+
Cross-language JWT toolkit (TypeScript + Python) with identical APIs. Automatically selects HS512 or EdDSA based on environment configuration, and supports ES512 and RSA for external OIDC verification. Loads secrets via Cloudflare bindings and works across Workers, Node.js, and Python runtimes.
2222

2323
## Part of the Flarelette Ecosystem
2424

@@ -88,7 +88,7 @@ const token = await signWithConfig({ sub: 'user123' }, config)
8888
const payload = await verifyWithConfig(token, config)
8989
```
9090

91-
> **New in v1.9.0:** The explicit configuration API eliminates environment setup complexity. See [Explicit Configuration Guide](./docs/explicit-config.md).
91+
> **New in v1.9.0:** The explicit configuration API eliminates environment setup complexity. See [Explicit Configuration Guide](./docs/user-guide/explicit-config.md).
9292
9393
### Basic Example (Environment-Based)
9494

@@ -145,7 +145,7 @@ Flarelette JWT Kit is designed to prevent common JWT vulnerabilities:
145145
**Mode selection is driven exclusively by server environment variables:**
146146

147147
- HS512 mode: `algorithms: ['HS512']` only
148-
- EdDSA/RSA mode: `algorithms: ['EdDSA', 'RS256', 'RS384', 'RS512']` only
148+
- EdDSA/ECDSA/RSA mode: `algorithms: ['EdDSA', 'ES256', 'ES384', 'ES512', 'RS256', 'RS384', 'RS512']` only
149149

150150
The `alg` header is treated as untrusted input and must match the allowed algorithms for the selected mode. Mismatches are rejected.
151151

@@ -239,7 +239,7 @@ When verifying tokens, the library uses the first available key source in this o
239239
## Documentation
240240

241241
- **[Getting Started](./docs/getting-started.md)** — Installation, first token, and basic setup
242-
- **[Explicit Configuration](./docs/explicit-config.md)** 🆕 — No environment setup required! Use config objects directly
242+
- **[Explicit Configuration](./docs/user-guide/explicit-config.md)** 🆕 — No environment setup required! Use config objects directly
243243
- **[Core Concepts](./docs/core-concepts.md)** — Algorithms, modes, and architecture
244244
- **[Usage Guide](./docs/usage-guide.md)** — Complete API reference for TypeScript and Python
245245
- **[Service Delegation](./docs/service-delegation.md)** — RFC 8693 actor claims for zero-trust
@@ -254,10 +254,12 @@ When verifying tokens, the library uses the first available key source in this o
254254
npx flarelette-jwt-secret --len=64 --dotenv
255255
```
256256

257-
**Generate EdDSA keypairs:**
257+
**Generate asymmetric keypairs (EdDSA default, or ES256/ES384/ES512):**
258258

259259
```bash
260-
npx flarelette-jwt-keygen --kid=ed25519-2025-01
260+
npx flarelette-jwt-keygen --kid=ed25519-2025-01 # EdDSA (default)
261+
npx flarelette-jwt-keygen --alg=ES512 --kid=es512-2025-01 # ECDSA P-521
262+
npx flarelette-jwt-keygen --alg=EdDSA --dotenv # Output as .env assignments
261263
```
262264

263265
## Contributing

THIRD_PARTY_LICENSES.md

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,9 @@ The TypeScript package depends on the following NPM packages:
1717
@flarelette/jwt-kit-env@1.8.1
1818
│ C:\Users\chris\git\flarelette-jwt-kit
1919
20-
└─┬ @chrislyons-dev/flarelette-jwt@1.12.0 -> .\packages\flarelette-jwt-ts
21-
Environment-driven JWT authentication for Cloudflare Workers with secret-name indirection
20+
└─┬ @chrislyons-dev/flarelette-jwt@1.14.0 -> .\packages\flarelette-jwt-ts
21+
2222
└── jose@6.1.3
23-
JWA, JWS, JWE, JWT, JWK, JWKS for Node.js, Browser, Cloudflare Workers, Deno, Bun, and other Web-interoperable runtimes
2423
```
2524

2625
---
@@ -77,4 +76,4 @@ This script:
7776

7877
---
7978

80-
**Last generated**: 2025-12-09
79+
**Last generated**: 2026-03-05

docs/architecture/.pages

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
nav:
2+
- README.md
3+
- exclude:
4+
- "*.md"

docs/architecture/README.md

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
# 🏗️ flarelette-jwt-kit
1+
# <img src="../images/archlette-stainedglassA-light.png" alt="" height="28" width="28" style="vertical-align:middle"> flarelette-jwt-kit
22

33
**Architecture Documentation**
4-
Generated 2025-12-08 19:38:11
4+
Generated 2026-03-05 17:59:12
55

66
## Overview
77

@@ -13,44 +13,25 @@ JWT authentication and authorization library
1313

1414
The system context diagram shows how flarelette-jwt-kit fits into its environment, including external systems and users.
1515

16-
![System Context Diagram](./diagrams/structurizr-SystemContext.png)
16+
<img src="./diagrams/structurizr-SystemContext.png" alt="System Context Diagram" style="max-width: 100%; height: auto;">
1717

1818
---
1919

2020
## Containers
2121

2222
The container diagram shows the high-level technology choices and how containers communicate.
2323

24-
![Container Diagram](./diagrams/structurizr-Containers.png)
25-
26-
<table>
27-
<thead>
28-
<tr>
29-
<th>Container</th>
30-
<th>Type</th>
31-
<th>Description</th>
32-
<th>Details</th>
33-
</tr>
34-
</thead>
35-
<tbody>
36-
<tr>
37-
<td><strong>@chrislyons-dev/flarelette-jwt</strong></td>
38-
<td><code>Service</code></td>
39-
<td>Environment-driven JWT authentication for Cloudflare Workers with secret-name indirection</td>
40-
<td><a href="./chrislyons_dev_flarelette_jwt.md">View →</a></td>
41-
</tr>
42-
<tr>
43-
<td><strong>flarelette-jwt</strong></td>
44-
<td><code>Service</code></td>
45-
<td>Environment-driven JWT authentication for Cloudflare Workers Python with secret-name indirection</td>
46-
<td><a href="./flarelette_jwt.md">View →</a></td>
47-
</tr>
48-
</tbody>
49-
</table>
24+
<img src="./diagrams/structurizr-Containers.png" alt="Container Diagram" style="max-width: 100%; height: auto;">
25+
26+
| Container | Type | Description | Details |
27+
| --- | --- | --- | --- |
28+
| **@chrislyons-dev/flarelette-jwt** | `Service` | TypeScript implementation of the Flarelette JWT Kit: An environment-driven JWT authentication package for Cloudflare Workers | [View](./chrislyons_dev_flarelette_jwt.md) |
29+
| **flarelette-jwt** | `Service` | Python implementation of the Flarelette JWT Kit: An environment-driven JWT authentication package for Cloudflare Workers | [View](./flarelette_jwt.md) |
5030

5131

5232
---
5333

5434
<div align="center">
5535
<sub>Generated with <a href="https://github.com/chrislyons-dev/archlette">Archlette</a> Architecture-as-Code toolkit</sub>
5636
</div>
37+

docs/architecture/chrislyons_dev_flarelette_jwt.md

Lines changed: 18 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -6,143 +6,43 @@
66

77
## Container Context
88

9-
![Container Diagram](./diagrams/structurizr-Containers.png)
9+
<img src="./diagrams/structurizr-Containers.png" alt="Container Diagram" style="max-width: 100%; height: auto;">
1010

1111
---
1212

1313
## Container Information
1414

15-
<table>
16-
<tbody>
17-
<tr>
18-
<td><strong>Name</strong></td>
19-
<td>@chrislyons-dev/flarelette-jwt</td>
20-
</tr>
21-
<tr>
22-
<td><strong>Type</strong></td>
23-
<td><code>Service</code></td>
24-
</tr>
25-
<tr>
26-
<td><strong>Description</strong></td>
27-
<td>Environment-driven JWT authentication for Cloudflare Workers with secret-name indirection</td>
28-
</tr>
29-
<tr>
30-
<td><strong>Tags</strong></td>
31-
<td><code>Auto-generated</code></td>
32-
</tr>
33-
</tbody>
34-
</table>
35-
15+
| Field | Value |
16+
| --- | --- |
17+
| **Name** | @chrislyons-dev/flarelette-jwt |
18+
| **Type** | `Service` |
19+
| **Description** | TypeScript implementation of the Flarelette JWT Kit: An environment-driven JWT authentication package for Cloudflare Workers || **Tags** | `Auto-generated` |
3620
---
3721

3822
## Components
3923

4024

4125
### Component View
4226

43-
![Component Diagram](./diagrams/structurizr-Components__chrislyons_dev_flarelette_jwt.png)
27+
<img src="./diagrams/structurizr-Components__chrislyons_dev_flarelette_jwt.png" alt="Component Diagram" style="max-width: 100%; height: auto;">
4428

4529
### Component Details
4630

47-
<table>
48-
<thead>
49-
<tr>
50-
<th>Component</th>
51-
<th>Type</th>
52-
<th>Description</th>
53-
<th>Code</th>
54-
</tr>
55-
</thead>
56-
<tbody>
57-
<tr>
58-
<td><strong>core</strong></td>
59-
<td><code>module</code></td>
60-
<td>CLI utility for generating JWT secrets.
61-
62-
This script provides options to generate secrets in various formats, including JSON and dotenv.
63-
It is designed to be executed as a standalone Node.js script. | Configuration utilities for JWT operations.
64-
65-
This module provides functions to read environment variables and derive JWT-related configurations.
66-
It includes support for both symmetric (HS512) and asymmetric (EdDSA) algorithms. | JWT signing utilities.
67-
68-
This module provides functions to sign JWT tokens using either HS512 or EdDSA algorithms.
69-
It supports custom claims and configuration overrides.</td>
70-
<td><a href="./chrislyons_dev_flarelette_jwt__core.md">View →</a></td>
71-
</tr>
72-
<tr>
73-
<td><strong>explicit</strong></td>
74-
<td><code>module</code></td>
75-
<td>Explicit configuration API for JWT operations.
76-
77-
This module provides functions that accept explicit configuration objects
78-
instead of relying on environment variables or global state. Use this API
79-
when you need full control over configuration, especially in development
80-
environments or when working with multiple JWT configurations.</td>
81-
<td><a href="./chrislyons_dev_flarelette_jwt__explicit.md">View →</a></td>
82-
</tr>
83-
<tr>
84-
<td><strong>util</strong></td>
85-
<td><code>module</code></td>
86-
<td>High-level JWT utilities for creating, delegating, verifying, and authorizing JWT tokens | Key generation utility for EdDSA keys.
87-
88-
This script generates EdDSA key pairs and exports them in JWK format.
89-
It is designed to be executed as a standalone Node.js script. | Secret generation and validation utilities.
90-
91-
This module provides functions to generate secure secrets and validate base64url-encoded secrets.
92-
It ensures compatibility with JWT signing requirements. | Utility functions for JWT operations.
93-
94-
This module provides helper functions for parsing JWTs, checking expiration, and mapping OAuth scopes.
95-
It is designed to support core JWT functionalities.</td>
96-
<td><a href="./chrislyons_dev_flarelette_jwt__util.md">View →</a></td>
97-
</tr>
98-
<tr>
99-
<td><strong>main</strong></td>
100-
<td><code>module</code></td>
101-
<td>Entry point for the flarelette-jwt library.
102-
103-
This module re-exports core functionalities, including signing, verification, utilities, and type definitions.
104-
It serves as the main interface for library consumers.</td>
105-
<td><a href="./chrislyons_dev_flarelette_jwt__main.md">View →</a></td>
106-
</tr>
107-
<tr>
108-
<td><strong>jwks</strong></td>
109-
<td><code>module</code></td>
110-
<td>JSON Web Key Set (JWKS) utilities.
111-
112-
This module provides functions to fetch and manage JWKS, including caching and key lookup by key ID (kid).
113-
It supports integration with external JWKS services.</td>
114-
<td><a href="./chrislyons_dev_flarelette_jwt__jwks.md">View →</a></td>
115-
</tr>
116-
<tr>
117-
<td><strong>types</strong></td>
118-
<td><code>module</code></td>
119-
<td>Type definitions for JWT operations.
120-
121-
This module defines types for JWT headers, payloads, profiles, and related structures.
122-
It ensures type safety and consistency across the library.</td>
123-
<td><a href="./chrislyons_dev_flarelette_jwt__types.md">View →</a></td>
124-
</tr>
125-
<tr>
126-
<td><strong>verify</strong></td>
127-
<td><code>module</code></td>
128-
<td>JWT verification utilities.
129-
130-
This module provides functions to verify JWT tokens using either HS512 or EdDSA algorithms.
131-
It supports integration with JWKS services and thumbprint pinning.</td>
132-
<td><a href="./chrislyons_dev_flarelette_jwt__verify.md">View →</a></td>
133-
</tr>
134-
<tr>
135-
<td><strong>adapters</strong></td>
136-
<td><code>module</code></td>
137-
<td>Component inferred from directory: adapters</td>
138-
<td><a href="./chrislyons_dev_flarelette_jwt__adapters.md">View →</a></td>
139-
</tr>
140-
</tbody>
141-
</table>
31+
| Component | Type | Description | Code |
32+
| --- | --- | --- | --- |
33+
| **core** | `module` | CLI utility for generating JWT secrets.<br><br>This script provides options to generate secrets in various formats, including JSON and dotenv.<br>It is designed to be executed as a standalone Node.js script. \| Configuration utilities for JWT operations.<br><br>This module provides functions to read environment variables and derive JWT-related configurations.<br>It includes support for both symmetric (HS512) and asymmetric (EdDSA) algorithms. \| JWT signing utilities.<br><br>This module provides functions to sign JWT tokens using either HS512 or EdDSA algorithms.<br>It supports custom claims and configuration overrides. | [View](./chrislyons_dev_flarelette_jwt__core.md) |
34+
| **explicit** | `module` | Explicit configuration API for JWT operations.<br><br>This module provides functions that accept explicit configuration objects<br>instead of relying on environment variables or global state. Use this API<br>when you need full control over configuration, especially in development<br>environments or when working with multiple JWT configurations. | [View](./chrislyons_dev_flarelette_jwt__explicit.md) |
35+
| **util** | `module` | High-level JWT utilities for creating, delegating, verifying, and authorizing JWT tokens \| Key generation utility for EdDSA and ECDSA keys.<br><br>Generates asymmetric key pairs and exports them in JWK format.<br>Designed to be executed as a standalone Node.js script. \| Secret generation and validation utilities.<br><br>This module provides functions to generate secure secrets and validate base64url-encoded secrets.<br>It ensures compatibility with JWT signing requirements. \| Utility functions for JWT operations.<br><br>This module provides helper functions for parsing JWTs, checking expiration, and mapping OAuth scopes.<br>It is designed to support core JWT functionalities. | [View](./chrislyons_dev_flarelette_jwt__util.md) |
36+
| **main** | `module` | Entry point for the flarelette-jwt library.<br><br>This module re-exports core functionalities, including signing, verification, utilities, and type definitions.<br>It serves as the main interface for library consumers. | [View](./chrislyons_dev_flarelette_jwt__main.md) |
37+
| **jwks** | `module` | JSON Web Key Set (JWKS) utilities.<br><br>This module provides functions to fetch and manage JWKS, including caching and key lookup by key ID (kid).<br>It supports integration with external JWKS services. | [View](./chrislyons_dev_flarelette_jwt__jwks.md) |
38+
| **types** | `module` | Type definitions for JWT operations.<br><br>This module defines types for JWT headers, payloads, profiles, and related structures.<br>It ensures type safety and consistency across the library. | [View](./chrislyons_dev_flarelette_jwt__types.md) |
39+
| **verify** | `module` | JWT verification utilities.<br><br>This module provides functions to verify JWT tokens using either HS512 or EdDSA algorithms.<br>It supports integration with JWKS services and thumbprint pinning. | [View](./chrislyons_dev_flarelette_jwt__verify.md) |
40+
| **adapters** | `module` | Component inferred from directory: adapters | [View](./chrislyons_dev_flarelette_jwt__adapters.md) |
14241

14342

14443
---
14544

14645
<div align="center">
14746
<sub><a href="./README.md">← Back to System Overview</a> | Generated with <a href="https://github.com/chrislyons-dev/archlette">Archlette</a></sub>
14847
</div>
48+

0 commit comments

Comments
 (0)