You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs: ready JWX plan for v0.6.0 cutover and ML-DSA
Go 1.27 is out; target jwx v4-only on httpsign v0.6.0 and treat
post-quantum ML-DSA via foreign JWS as an explicit goal.
Co-authored-by: Cursor <cursoragent@cursor.com>
Copy file name to clipboardExpand all lines: internal-docs/JWX.md
+85-41Lines changed: 85 additions & 41 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,79 +4,120 @@ Single source of truth for optional jwx-backed JWS support in httpsign.
4
4
5
5
## Role in httpsign
6
6
7
-
jwx is used only for **optional “foreign” JWS** signing and verification (`NewJWSSigner` / `NewJWSVerifier` on jwx v2, and `NewJWSSignerV3` / `NewJWSVerifierV3` on jwx v3). **Native** algorithms (HMAC-SHA256, RSA, RSASSA-PSS, P-256/P-384, Ed25519) do **not** use jwx.
7
+
jwx is used only for **optional “foreign” JWS** signing and verification. **Native** algorithms (HMAC-SHA256, RSA, RSASSA-PSS, P-256/P-384, Ed25519) do **not** use jwx.
8
8
9
-
Today `go.mod` pulls both `github.com/lestrrat-go/jwx/v2` and `.../jwx/v3`. `crypto.go` dispatches on the embedded foreign signer/verifier interfaces (v2 vs v3 parameter order differs).
9
+
**Today (pre-cutover):**`go.mod`still pulls both `github.com/lestrrat-go/jwx/v2` and `.../jwx/v3`. Public API is `NewJWSSigner` / `NewJWSVerifier` (v2) and `NewJWSSignerV3` / `NewJWSVerifierV3` (v3). `crypto.go` dispatches on the embedded foreign signer/verifier interfaces (v2 vs v3 parameter order differs).
10
10
11
-
## Current policy (until Go 1.27)
11
+
**Target:** a single jwx **v4** path, one constructor pair, and **post-quantum (PQ) signatures** as a first-class capability (see below).
12
12
13
-
- Stay on the dual v2+v3 paths.
14
-
- Bump **within `jwx/v3`** (patch/minor) if needed for fixes.
15
-
- Do **not** adopt jwx v4 on Go 1.24 / 1.26 + `GOEXPERIMENT=jsonv2`.
16
-
- Do **not** deprecate only the v2 constructors (“use V3”) — that would send callers to V3 and then remove V3 in the next major.
13
+
**Release vehicle:** ship as **httpsign `v0.6.0`** (breaking within `0.x`; not a leap to `v1.0.0`). Under Go modules, `v0.y.z` may introduce breaking API/dependency changes on a minor bump — that is intentional here (Go floor, drop jwx v2/v3, collapse constructors).
17
14
18
-
## Decision: all-in on jwx v4 after Go 1.27 stable
15
+
---
16
+
17
+
## Explicit goals
18
+
19
+
1.**Drop dual jwx support** — cut over to **jwx v4 only** on **Go 1.27+**, released as **`v0.6.0`**. Details in the next sections.
20
+
2.**PQ signatures** — make **ML-DSA (FIPS 204)** usable for RFC 9421 HTTP Message Signatures through httpsign’s foreign-JWS path (and document it), in **`v0.6.0`** or a fast follow (`v0.6.x` / `v0.7.0` only if PQ slips).
21
+
22
+
### PQ signatures (goal detail)
23
+
24
+
Go 1.27 adds stdlib [`crypto/mldsa`](https://pkg.go.dev/crypto/mldsa). jwx v4 registers **ML-DSA-44 / ML-DSA-65 / ML-DSA-87** natively when built with Go 1.27+ (`jwa.MLDSA44()`, `MLDSA65()`, `MLDSA87()`; `*mldsa.PrivateKey` / `*mldsa.PublicKey` work with `jws.Signer` / `jws.Verifier`). The companion [`github.com/jwx-go/mldsa/v4`](https://github.com/jwx-go/mldsa) is **not** required on our Go floor.
25
+
26
+
**In scope for httpsign**
27
+
28
+
- After the v4 cutover, `NewJWSSigner` / `NewJWSVerifier` must accept ML-DSA algs + `crypto/mldsa` keys the same way they accept classical JWS algs (no special `GOEXPERIMENT`, no optional build tags).
29
+
- Round-trip tests: sign and verify an HTTP request (or signature base) with at least one parameter set (prefer **ML-DSA-65** as the default demo; cover 44/87 if cheap).
30
+
- README / release notes: call out PQ via foreign JWS; note that RFC 9421 does not assign HTTP-sig algorithm identifiers for ML-DSA — callers use the JWS/`alg` story (or omit `alg` per profile) as with other foreign algorithms.
31
+
- Reject `NoSignature` and other unsafe algs unchanged.
32
+
33
+
**Out of scope (for now)**
34
+
35
+
-**Native**`NewMLDSASigner`-style constructors that bypass jwx (revisit only if foreign-JWS overhead or API clarity demands it).
36
+
-**Hybrid composite** signatures ([`jwx-go/compsig`](https://github.com/jwx-go/compsig), draft-ietf-jose-pq-composite-sigs) — track as a follow-on once the draft and companion stabilize.
**Agreed (2026-07):**once **Go 1.27.0** (stable, not RC) is out, cut over httpsign to **`github.com/lestrrat-go/jwx/v4` only** (pin **v4.2.0+**) as an **httpsign major**.
39
+
**Why fold PQ into this work:**the Go 1.27 + jwx v4 cutover is exactly what unlocks stdlib ML-DSA without experiments or extra modules. Shipping `v0.6.0` without exercising PQ would leave the main benefit of the floor unused.
21
40
22
-
### Why wait for 1.27
41
+
---
42
+
43
+
## Status (2026-08-26): execute the cutover
44
+
45
+
The July 2026 gate is **met**. Do **`v0.6.0`** now; do **not** keep dual v2+v3 any longer than the cutover PR.
23
46
24
-
-**Go 1.26:**`encoding/json/v2` still needs `GOEXPERIMENT=jsonv2`; jwx v4 would force that on every httpsign build.
25
-
-**Go 1.27:**`encoding/json/v2` / `jsontext` are stdlib packages; `encoding/json` is backed by v2. Opt-out is `GOEXPERIMENT=nojsonv2` (temporary). See [go1.27 notes](https://go.dev/doc/go1.27), [golang/go#71497](https://github.com/golang/go/issues/71497), [golang/go#76406](https://github.com/golang/go/issues/76406).
26
-
- jwx **v4.2.0** (2026-07-24) is mature enough; the gate is the Go toolchain, not jwx.
47
+
| Gate | Status |
48
+
|------|--------|
49
+
| Go **1.27.0** stable on [go.dev/dl](https://go.dev/dl/)|**Met** (released 2026-08-19) |
50
+
|`encoding/json/v2` in stdlib (no `GOEXPERIMENT=jsonv2`) |**Met** — see [Go 1.27 notes](https://go.dev/doc/go1.27)|
51
+
| jwx v4 mature |**Met** — use **`v4.4.0+`** (v4.2.0 was the original floor; current latest as of this update is v4.4.0) |
52
+
| Smoke: `go get …/jwx/v4@v4.4.0` under `GOTOOLCHAIN=go1.27.0`, no `GOEXPERIMENT`|**Confirmed** locally (2026-08-26) |
53
+
| Stdlib **`crypto/mldsa`** + jwx native ML-DSA (PQ goal) |**Met** on Go 1.27+ (no `jwx-go/mldsa` companion needed) |
27
54
28
-
### Trigger to implement
55
+
### Why this was deferred (history)
29
56
30
-
1. Go **1.27.0** available on `go.dev/dl`.
31
-
2. Confirm `go get github.com/lestrrat-go/jwx/v4@v4.2.0` (or newer) builds **without**`GOEXPERIMENT=jsonv2` under Go 1.27.
32
-
3. Ship the cutover as an httpsign **major**.
57
+
- On Go 1.26, jwx v4 required `GOEXPERIMENT=jsonv2` on every httpsign build — rejected for a library.
58
+
- Dual v2+v3 was an interim; we deliberately avoided a “deprecate v2 → use V3” step that would bounce callers twice.
59
+
-**Agreed (2026-07):** all-in on jwx v4 after Go 1.27 stable, as a **breaking** httpsign release.
60
+
-**Agreed (2026-08-26):** Go 1.27 is out; **start the cutover** and ship it as **`v0.6.0`** (not `v1.0.0`).
61
+
62
+
---
63
+
64
+
## Decision: all-in on jwx v4 (`v0.6.0`)
65
+
66
+
Cut over to **`github.com/lestrrat-go/jwx/v4` only**, pin **≥ v4.4.0**, drop v2 and v3 in **`v0.6.0`**.
33
67
34
68
### What the cutover does
35
69
70
+
- Raise `go` / toolchain / CI to **Go 1.27.0+**.
36
71
- Drop `jwx/v2` and `jwx/v3` from `go.mod`.
37
-
- Single constructor pair on v4 types (preferred names: `NewJWSSigner` / `NewJWSVerifier`; remove `*V3`).
38
-
- Update CI / `go` directive to **1.27.0+**.
39
-
- Follow upstream [MIGRATION.md](https://github.com/lestrrat-go/jwx/blob/v4.2.0/MIGRATION.md) and optionally [jwxmigrate](https://github.com/jwx-go/jwxmigrate).
40
-
- Re-run foreign-JWS tests; note v4 behavioral tightenings in [Changes-v4.md](https://github.com/lestrrat-go/jwx/blob/v4.2.0/Changes-v4.md).
72
+
- Single constructor pair on v4 types: **`NewJWSSigner` / `NewJWSVerifier`** (remove `*V3`; retire the v2-typed overloads).
73
+
- Follow upstream [MIGRATION.md](https://github.com/lestrrat-go/jwx/blob/v4.4.0/MIGRATION.md) and optionally [jwxmigrate](https://github.com/jwx-go/jwxmigrate) (`jwxmigrate/v4`).
74
+
- Re-run foreign-JWS tests (classical + **ML-DSA**); note behavioral tightenings in [Changes-v4.md](https://github.com/lestrrat-go/jwx/blob/v4.4.0/Changes-v4.md) if any affect jwa/jws-only use.
75
+
- Update `CLAUDE.md` / README snippets that still recommend dual v2/v3 or `*V3`; document PQ via foreign JWS.
76
+
- Tag and release **`v0.6.0`**.
41
77
42
78
### Deprecation / messaging
43
79
44
-
-**No** mid-stream v2→V3-only deprecation.
45
-
- Either remove v2 and `*V3` together in the major with a short migration note, **or** add `// Deprecated:` on **both** only when announcing that major (pointing at the new v4-backed constructors) — never “prefer V3” as a stable end state.
80
+
-**No** mid-stream “prefer V3” deprecation before `v0.6.0`.
81
+
- In `v0.6.0`: remove v2 constructors and `*V3` together; release notes document the caller steps below.
82
+
- Optional: if a short transition branch is needed for review only, both old APIs may carry `// Deprecated:` pointing at the v4-backed `NewJWS*` — never ship “V3 is the stable end state.”
46
83
47
-
### Customer impact (v3 → v4)
84
+
### Customer impact
48
85
49
-
Typical callers of `NewJWSSignerV3` / `NewJWSVerifierV3` only pass a `jwa` algorithm, a key, and httpsign config/fields. Expected change:
86
+
| Caller | Change |
87
+
|--------|--------|
88
+
|**Native algorithms only**| Go **1.27+** floor; otherwise unaffected |
89
+
|**`NewJWSSignerV3` / `NewJWSVerifierV3`**| Bump to **`v0.6.0`**; import `jwx/v3/jwa` → `jwx/v4/jwa`; rename to `NewJWSSigner` / `NewJWSVerifier` (v4 `jwa` uses function forms like `jwa.ES256()`) |
90
+
|**`NewJWSSigner` / `NewJWSVerifier` (v2)**| Same release: switch to v4 imports + v4 algorithm values; no separate `*V3` step |
50
91
51
-
1. Go **1.27+**
52
-
2. httpsign **major**
53
-
3. Import `jwx/v3/jwa` → `jwx/v4/jwa`
54
-
4. Rename `NewJWS*V3` → `NewJWS*` (if we collapse names)
55
-
56
-
No change to key types or httpsign signing/verify config. **Native-algorithm users** are unaffected aside from the Go version floor. Exotic jwx features (ES256K companions, custom jwx signers, JWKS fetch) are out of scope for most httpsign users.
92
+
No change to key types or httpsign `SignConfig` / `VerifyConfig` / `Fields` for classical callers. **PQ callers** bring `crypto/mldsa` keys and `jwa.MLDSA*()` through the same `NewJWS*` constructors. ES256K / Ed448 companions, custom jwx signers, and JWKS fetch remain niche; composite PQ is a later follow-on (see Explicit goals).
57
93
58
94
### Toolchain after cutover
59
95
60
96
| Item | Requirement |
61
97
|------|-------------|
62
-
| Go |**1.27.0+** in `go.mod` / CI |
63
-
|`GOEXPERIMENT=jsonv2`| Not required on Go 1.27+|
98
+
| Go |**1.27.0+** in `go.mod` / CI (today CI is still 1.24) |
99
+
|`GOEXPERIMENT=jsonv2`| Not required; do not set|
64
100
|`GOEXPERIMENT=nojsonv2`| Avoid in CI |
65
101
102
+
Upstream still allows Go 1.26 + `GOEXPERIMENT=jsonv2` for jwx v4; **httpsign will not support that** — floor is 1.27 so consumers never need the experiment.
103
+
66
104
---
67
105
68
-
## Implementation checklist (when Go 1.27 is out)
106
+
## Implementation checklist (do now)
69
107
70
-
Scoped to httpsign’s use of **jwa** + **jws** only (no JWT/JWE/JWK fetch in library glue). Full upstream detail: [MIGRATION.md](https://github.com/lestrrat-go/jwx/blob/v4.2.0/MIGRATION.md).
108
+
Scoped to httpsign’s use of **jwa** + **jws** only (no JWT/JWE/JWK fetch in library glue). Upstream detail: [MIGRATION.md (v4.4.0)](https://github.com/lestrrat-go/jwx/blob/v4.4.0/MIGRATION.md).
71
109
72
110
### Code / deps
73
111
74
-
-[ ]`go.mod`: Go 1.27.0+; require `github.com/lestrrat-go/jwx/v4` (≥ v4.2.0); remove v2 and v3.
Copy file name to clipboardExpand all lines: internal-docs/README.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -4,7 +4,7 @@ This directory contains internal documentation for maintainers of the httpsign l
4
4
5
5
## Contents
6
6
7
-
-**JWX.md** — Optional jwx / foreign-JWS support: current dual v2/v3 state, and the plan to move to **jwx v4.2.0+** after**Go 1.27 stable**(httpsign major).
7
+
-**JWX.md** — Optional jwx / foreign-JWS: cut over to jwx v4.4.0+ on Go 1.27+ as **httpsign `v0.6.0`**, with**ML-DSA PQ signatures**as an explicit goal. Gate met 2026-08-26.
0 commit comments