|
| 1 | +# jwx / foreign JWS plan (maintainers) |
| 2 | + |
| 3 | +Single source of truth for optional jwx-backed JWS support in httpsign. |
| 4 | + |
| 5 | +## Role in httpsign |
| 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. |
| 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). |
| 10 | + |
| 11 | +## Current policy (until Go 1.27) |
| 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. |
| 17 | + |
| 18 | +## Decision: all-in on jwx v4 after Go 1.27 stable |
| 19 | + |
| 20 | +**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**. |
| 21 | + |
| 22 | +### Why wait for 1.27 |
| 23 | + |
| 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. |
| 27 | + |
| 28 | +### Trigger to implement |
| 29 | + |
| 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**. |
| 33 | + |
| 34 | +### What the cutover does |
| 35 | + |
| 36 | +- 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). |
| 41 | + |
| 42 | +### Deprecation / messaging |
| 43 | + |
| 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. |
| 46 | + |
| 47 | +### Customer impact (v3 → v4) |
| 48 | + |
| 49 | +Typical callers of `NewJWSSignerV3` / `NewJWSVerifierV3` only pass a `jwa` algorithm, a key, and httpsign config/fields. Expected change: |
| 50 | + |
| 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. |
| 57 | + |
| 58 | +### Toolchain after cutover |
| 59 | + |
| 60 | +| Item | Requirement | |
| 61 | +|------|-------------| |
| 62 | +| Go | **1.27.0+** in `go.mod` / CI | |
| 63 | +| `GOEXPERIMENT=jsonv2` | Not required on Go 1.27+ | |
| 64 | +| `GOEXPERIMENT=nojsonv2` | Avoid in CI | |
| 65 | + |
| 66 | +--- |
| 67 | + |
| 68 | +## Implementation checklist (when Go 1.27 is out) |
| 69 | + |
| 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). |
| 71 | + |
| 72 | +### Code / deps |
| 73 | + |
| 74 | +- [ ] `go.mod`: Go 1.27.0+; require `github.com/lestrrat-go/jwx/v4` (≥ v4.2.0); remove v2 and v3. |
| 75 | +- [ ] Rewrite imports `jwx/v2|v3` → `jwx/v4`; collapse constructors; update `sign()` / `verify()` dispatch for v4 `jws.Signer` / `jws.Verifier` (ex-`Signer2` / `Verifier2`). |
| 76 | +- [ ] Confirm factory APIs (`SignerFor` / `VerifierFor` or v4 equivalents) and `NoSignature` rejection still work. |
| 77 | +- [ ] Run `jwxmigrate` if helpful; fix remaining compile/test failures by hand. |
| 78 | +- [ ] CI: Go 1.27; do not set `jsonv2` / `nojsonv2` experiments. |
| 79 | +- [ ] Release notes: httpsign major; document caller steps above; link upstream Changes-v4 if relevant. |
| 80 | + |
| 81 | +### Upstream items likely N/A or low priority |
| 82 | + |
| 83 | +| Topic | httpsign | |
| 84 | +|-------|----------| |
| 85 | +| JWK `Import` generics, `ParseFS`, custom field registration | Unlikely / N/A | |
| 86 | +| HTTP JWKS → `jwkfetch` | N/A in core; document if examples ever use `jku` | |
| 87 | +| ES256K / Ed448 / asmbase64 companions | Only if we expose or test those algs | |
| 88 | +| Custom `Signer`/`Verifier` with `Algorithm()` | We embed upstream implementations only — re-check types after rename | |
| 89 | +| Detached payload `io.Reader` | Orthogonal (we sign the RFC 9421 base string as `[]byte`) | |
0 commit comments