lestrrat-go/jwx

GitHub: lestrrat-go/jwx

Go 语言下完整实现 JOSE/JWx 全套规范(JWT、JWS、JWE、JWK、JWA)的密码学与身份令牌处理库。

Stars: 2405 | Forks: 193

# github.com/lestrrat-go/jwx/v4 [![CI](https://static.pigsec.cn/wp-content/uploads/repos/cas/ad/ad5834178f7599af9fdda11629d49cae07f2997beec49821b2920eff5bfd50e7.svg)](https://github.com/lestrrat-go/jwx/actions/workflows/ci.yml) [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/jwx/v4.svg)](https://pkg.go.dev/github.com/lestrrat-go/jwx/v4) [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/lestrrat-go/jwx) Go module 实现了各种 JWx(JWA/JWE/JWK/JWS/JWT,也称为 JOSE)技术。 如果您正在您的产品或公司中使用此 module,请在 [Wiki](https://github.com/lestrrat-go/jwx/wiki/Users) 中添加您的产品和/或公司名称!这真的有助于保持我们的动力。 # 环境要求 * Go 1.26 或更高版本 * `GOEXPERIMENT=jsonv2` # 安装 ``` go get github.com/lestrrat-go/jwx/v4 ``` ## Claude Code Skill 如果您使用 [Claude Code](https://claude.com/claude-code),请安装内置的 `jwx-dev-v4` skill,这样助手就能指导您使用该库——包括选择算法、解析/签名 JWT、使用 JWS/JWE/JWK,并避免常见的陷阱: ``` /plugin marketplace add lestrrat-go/jwx /plugin install jwx-dev-v4 ``` 此 skill 仅适用于 **v4**。它面向*使用* jwx 的开发者,而不是用于开发库本身。 # 从 v3 迁移 如果您正在从 `github.com/lestrrat-go/jwx/v3` 迁移,请参阅 [`MIGRATION.md`](MIGRATION.md) 获取包含修改前后代码示例的逐步指南。有关破坏性变更和新功能的完整列表,请参阅 [`Changes-v4.md`](Changes-v4.md)。 # 功能 | 功能 | 描述 | |---------|-------------| | **全面的 JWA/JWE/JWK/JWS/JWT 覆盖** | 不仅仅是 JWT + 最小工具集。支持带有多个签名的 JWS 消息(compact 和 JSON 序列化)、带有 detached payload 的 JWS、带有 unencoded payload 的 JWS (RFC 7797),以及带有多个接收者的 JWE 消息(compact 和 JSON 序列化)。大多数操作可以使用 JWK 或原始密钥(例如 `*rsa.PrivateKey`、`*ecdsa.PrivateKey`)。 | | **具有主见且统一的 API** | 一切都是对称的,并遵循标准约定:`jws.Parse`/`Verify`/`Sign`,`jwe.Parse`/`Encrypt`/`Decrypt`。参数被组织为明确的必填参数和可选的 `WithXXXX()` 风格选项。 | | **后量子密码学** | 支持 ML-KEM、ML-DSA 和 HPKE。 | | **扩展 module 架构** | 通过扩展 module 提供可选功能。请参阅[扩展 Module](docs/10-extensions.md)。 | | **JWK 缓存** | [`jwkfetch`](https://github.com/jwx-go/jwkfetch) 扩展,用于始终保持 JWKS 最新。 | | **Bazel 支持** | 支持 [Bazel](https://bazel.build)。 | # 概要 ``` package examples_test import ( "bytes" "fmt" "net/http" "time" "github.com/lestrrat-go/jwx/v4/jwa" "github.com/lestrrat-go/jwx/v4/jwe" "github.com/lestrrat-go/jwx/v4/jwk" "github.com/lestrrat-go/jwx/v4/jws" "github.com/lestrrat-go/jwx/v4/jwt" ) func Example() { // Parse, serialize, slice and dice JWKs! privkey, err := jwk.ParseKey(jsonRSAPrivateKey) if err != nil { fmt.Printf("failed to parse JWK: %s\n", err) return } pubkey, err := jwk.PublicKeyOf(privkey) if err != nil { fmt.Printf("failed to get public key: %s\n", err) return } // Work with JWTs! { // Build a JWT! tok, err := jwt.NewBuilder(). Issuer(`github.com/lestrrat-go/jwx`). IssuedAt(time.Now()). Build() if err != nil { fmt.Printf("failed to build token: %s\n", err) return } // Sign a JWT! signed, err := jwt.Sign(tok, jwt.WithKey(jwa.RS256(), privkey)) if err != nil { fmt.Printf("failed to sign token: %s\n", err) return } // Verify a JWT! { verifiedToken, err := jwt.Parse(signed, jwt.WithKey(jwa.RS256(), pubkey)) if err != nil { fmt.Printf("failed to verify JWS: %s\n", err) return } _ = verifiedToken } // Work with *http.Request! { req, _ := http.NewRequest(http.MethodGet, `https://github.com/lestrrat-go/jwx`, nil) req.Header.Set(`Authorization`, fmt.Sprintf(`Bearer %s`, signed)) verifiedToken, err := jwt.ParseRequest(req, jwt.WithKey(jwa.RS256(), pubkey)) if err != nil { fmt.Printf("failed to verify token from HTTP request: %s\n", err) return } _ = verifiedToken } } // Encrypt and Decrypt arbitrary payload with JWE! { encrypted, err := jwe.Encrypt(payloadLoremIpsum, jwe.WithKey(jwa.RSA_OAEP_256(), jwkRSAPublicKey)) if err != nil { fmt.Printf("failed to encrypt payload: %s\n", err) return } decrypted, err := jwe.Decrypt(encrypted, jwe.WithKey(jwa.RSA_OAEP_256(), jwkRSAPrivateKey)) if err != nil { fmt.Printf("failed to decrypt payload: %s\n", err) return } if !bytes.Equal(decrypted, payloadLoremIpsum) { fmt.Printf("verified payload did not match\n") return } } // Sign and Verify arbitrary payload with JWS! { signed, err := jws.Sign(payloadLoremIpsum, jws.WithKey(jwa.RS256(), jwkRSAPrivateKey)) if err != nil { fmt.Printf("failed to sign payload: %s\n", err) return } verified, err := jws.Verify(signed, jws.WithKey(jwa.RS256(), jwkRSAPublicKey)) if err != nil { fmt.Printf("failed to verify payload: %s\n", err) return } if !bytes.Equal(verified, payloadLoremIpsum) { fmt.Printf("verified payload did not match\n") return } } // OUTPUT: } ``` 源码: [examples/jwx_readme_example_test.go](https://github.com/jwx-go/examples/blob/v4/jwx_readme_example_test.go) # 文档 * [API 参考](https://pkg.go.dev/github.com/lestrrat-go/jwx/v4) * [操作指南文档](./docs) * [可运行示例](https://github.com/jwx-go/examples) * [扩展 Module](docs/10-extensions.md) # 包和标准 此 module 实现了以下规范: | 包 | 规范 | |---------|---------------| | [jwa](./jwa) | [RFC 7518](https://tools.ietf.org/html/rfc7518) (JSON Web Algorithms) | | [jwk](./jwk) | [RFC 7517](https://tools.ietf.org/html/rfc7517) (JSON Web Key), [RFC 7638](https://tools.ietf.org/html/rfc7638) (JWK Thumbprint), [RFC 8037](https://tools.ietf.org/html/rfc8037) (CFRG Curves) | | [jws](./jws) | [RFC 7515](https://tools.ietf.org/html/rfc7515) (JSON Web Signature), [RFC 7797](https://tools.ietf.org/html/rfc7797) (Unencoded Payload) | | [jwe](./jwe) | [RFC 7516](https://tools.ietf.org/html/rfc7516) (JSON Web Encryption), [draft-ietf-jose-hpke-encrypt](https://datatracker.ietf.org/doc/draft-ietf-jose-hpke-encrypt/) (HPKE) | | [jwt](./jwt) | [RFC 7519](https://tools.ietf.org/html/rfc7519) (JSON Web Token) | 此外,通过主 module 或[扩展 module](docs/10-extensions.md) 还提供了额外支持: ## 历史 我的目标是编写一个大量使用 JWK 和 JWT 的服务器。乍一看, 已有的库似乎足够了,但很快我意识到 1. 要完全实现这些协议,我需要完整的 JWT、JWK、JWS、JWE(以及必然需要的 JWA)。 2. 现存的大多数库只处理各种 JWx 规范中的一部分,这些只是实现它们特定需求所必需的。 因为我正在编写服务器端(以及用于测试的客户端),我需要*整个* JOSE 工具集来正确实现我的服务器,**并且**它们需要足够*灵活*以满足我正在编写的整个规范。 所以就有了 `github.com/lestrrat-go/jwx/v4`。这个库是可扩展的、可定制的,并且组织得很好,方便您轻松地对它进行切割和取舍。 ## 为什么我要使用这个库? 还有其他几个主要的 Go module 可以处理 JWT 和相关数据格式, 那么为什么您应该使用这个库呢? 从纯粹的功能角度来看,唯一的主要区别是: 虽然大多数其他项目只处理它们认为处理 JWT 所必需的内容, 但这个 module 处理 JWS、JWE、JWK 和 JWT 的**_整个_**范畴。 也就是说,如果您不仅需要解析 JWT,还需要控制 JWK,或者 如果您需要处理不是 JWT 的 payload,您应该考虑 使用这个 module。您还应该注意,JWT 是构建在这些 其他技术*之上*的。如果没有实现 JWS/JWE/JWK 的全部功能,您根本无法拥有一个完整的 JWT 包,而这个库做到了这一点。 其次,从实现的角度来看,这个 module 与其他库有明显不同, 因为它非常努力地只暴露 API,而不暴露 内部数据。例如,不能通过 struct field 查找来访问单个 JWT claim。您需要使用其中一种 getter 方法。 这是因为这个库的立场是,最终用户在遇到宽松的 API 时,完全有能力甚至很乐意搬起石头砸自己的脚。通过确保用户无法访问未封闭的 struct,我们可以保护用户不做诸如创建*不完整*的 struct,或者在没有任何保护的情况下并发访问 struct 之类的蠢事。这种结构还允许我们在 struct 中注入额外的智能,例如,当您想解析/写入自定义字段时做正确的事情(这个 module 不需要用户指定备用 struct 来解析带有自定义字段的对象)。 归根结底,我认为这取决于您的使用模式和优先级。 我想到的一些一般性指导原则是: * 如果您想用一个库来处理所有与 JWx 相关的事情,比如使用 JWE、JWK、JWS,处理[自动刷新 JWK](https://github.com/jwx-go/jwkfetch),请使用此 module。 * 如果您想透明地兑现所有可能的自定义字段,请使用此 module。 * 如果您想要一个标准化且干净的 API,请使用此 module。 否则,请随意选择其他库。 # 贡献 ## Issues ## Pull Requests 请确保包含测试,以验证您所做的更改。 如果您正在编辑自动生成的文件(带有 `_gen.go` 后缀的文件),请确保您执行了以下操作: 1. 修改生成器,而不是生成的文件(例如 `internal/jwxcodegen/cmd/jwxcodegen/`) 2. 运行 `make generate`(或 `go generate`)来生成新代码 3. 同时提交生成器_和_生成的文件 ## 讨论 / 用法 请先尝试[讨论区](https://github.com/lestrrat-go/jwx/discussions)。 # 交换条件 如果您使用此软件在盈利性组织中构建产品,我们请求您_考虑_ 按以下方式回馈 FOSS: 这_不是_许可条款:您仍然可以根据该软件附带的许可证自由使用它。此条款仅是对人们的一种呼吁,希望大家能够认可 FOSS 开发者的工作,您每天都在依赖他们的成果。
标签:EVTX分析, 日志审计