jwx-companion-bulk
Apply bulk operations across all jwx companion modules. Args: <instructions...>
Guide for developing Go applications with github.com/lestrrat-go/jwx v4 — parse/sign JWTs, work with JWS/JWE/JWK, pick algorithms, and avoid the common footguns. For developers using jwx, not for developing the library itself.
$ npx -y skills add lestrrat-go/jwx --skill guide --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/guideContext preview
The summary Claude sees to decide when to auto-load this skill.
Guide for developing Go applications with github.com/lestrrat-go/jwx v4 — parse/sign JWTs, work with JWS/JWE/JWK, pick algorithms, and avoid the common footguns. For developers using jwx, not for developing the library itself.
name: jwx-guide-v4 description: Guide for developing Go applications with github.com/lestrrat-go/jwx v4 — parse/sign JWTs, work with JWS/JWE/JWK, pick algorithms, and avoid the common footguns. For developers using jwx, not for developing the library itself.
This skill helps you assist Go developers who are **using** `github.com/lestrrat-go/jwx/v4` in their own projects. It is scoped to **v4** only. There is no equivalent skill for v3 or v2; for those, work from the version's own `docs/` directory and pkg.go.dev. Do not apply v4 rules to a v3 or v2 codebase — the `jwa` identifiers are constants there, not functions, and the `jwk` and error APIs differ.
You will not have this repository checked out. To verify an API claim before answering, use these sources, in order of preference:
1. **Go module cache** — if the user's project depends on jwx, the source is on disk:
echo "$(go env GOMODCACHE)/github.com/lestrrat-go/jwx/v4@$(go list -m -f '{{.Version}}' github.com/lestrrat-go/jwx/v4)"This directory contains the full source tree including `docs/`, `jwt/`, `jws/`, `jwe/`, `jwk/`, `jwa/`. 2. **pkg.go.dev** — canonical API reference for any exported symbol:
3. **GitHub** — narrative documentation lives at the repo:
4. **Examples repo** — runnable usage patterns. The repo's `README.md` is a topical index that maps "what do I want to do" → "which `*_example_test.go` file." Fetch the README first when looking for an example by topic; then fetch the linked file:
When the user's question goes beyond the patterns in this skill (custom claim types, JWE recipients with per-recipient headers, custom key providers, base64 backend swap, performance tuning), fetch from these sources rather than guessing.
Sub-package map:
| Package | Role | |---------|------| | `jwa` | Algorithm identifiers as **functions**: `jwa.RS256()`, `jwa.ES256()`, `jwa.HS256()`, `jwa.A256GCM()`, `jwa.RSA_OAEP_256()`, `jwa.EdDSAEd25519()`, etc. | | `jwk` | JSON Web Keys: parsing, generating, import/export between `jwk.Key` and `crypto.*` keys, key sets. | | `jws` | Sign and verify arbitrary payloads (compact or JSON serialization). | | `jwe` | Encrypt and decrypt arbitrary payloads. | | `jwt` | JWT tokens — claims, signing, verification + validation. Wraps `jws`. | | `jwt/openid` | OpenID Connect ID-token-flavored claims. |
1. **`jwt.Parse` verifies AND validates by default.** A bare `jwt.Parse(data)` errors because no key was supplied. To intentionally skip both, use `jwt.ParseInsecure`. To verify but skip claim validation, pass `jwt.WithValidate(false)`. This is deliberately asymmetric vs. `jws.Parse`/`jwe.Parse` (which only parse). Do not "correct" it. 2. **Always pin the algorithm on the verify side.** `jwt.WithKey(jwa.RS256(), key)`, `jws.WithKey(jwa.ES256(), key)`. Never trust the `alg` from the incoming header alone. 3. **Never use `jwt.ParseInsecure` for tokens received from the network.** It is for testing or for extracting claims from a token whose origin is already trusted by other means. 4. **`jwa` algorithms are functions in v4, not constants.** Write `jwa.RS256()`, not `jwa.RS256`. This trips up users migrating from v2/v3. 5. **`kid` matching is enforced when verifying with a JWK Set.** If a token omits `kid` and the set contains exactly one key, use `jwt.WithKeySet(set, jws.WithUseDefault(true))`. Use `jws.WithRequireKid(false)` only when verification must consider multiple keys without matching `kid` values. 6. **`jku` (key URL in the JWS header) is attacker-controlled.** Use `jwt.WithVerifyAuto` only with a `jwkfetch.Client` configured with a `jwkfetch.NewMapWhitelist()` of allowed URLs. 7. **HMAC keys are `[]byte`, not `string`.** Pass `[]byte("secret")`, or better, a `jwk.Key` imported from those bytes. 8. **`jwk.Import` and `jwk.Export` require explicit type parameters.** `jwk.Import[jwk.Key](raw)`, `jwk.Export[*rsa.PublicKey](key)`. Their type argument is not inferable from the call, so bare `jwk.Import(raw)` does **not** compile. 9. **`jwk.ParseKey` is not generic.** `jwk.ParseKey(data)` returns `(jwk.Key, error)`. Use `jwk.ParseKeyAs[jwk.RSAPublicKey](data)` when a concrete JWK type is required.
import (
"github.com/lestrrat-go/jwx/v4/jwa"
"github.com/lestrrat-go/jwx/v4/jwt"
)
tok, err := jwt.Parse(raw, jwt.WithKey(jwa.RS256(), publicKey))
if err != nil {
// signature failed, claim validation failed, or parse failed
return err
}
// tok is verified + validated; safe to read claims`publicKey` may be:
To validate against expected claim values, pass `jwt.WithIssuer(
Go module implementing various JWx (JWA/JWE/JWK/JWS/JWT, otherwise known as JOSE) technologies. If you are using this module in your product or your company, please add your product and/or company name in the Wiki! It really helps keeping up our motivation.
Repo: lestrrat-go/jwx
Apply bulk operations across all jwx companion modules. Args: <instructions...>