github.com/lestrrat-go/jwx/v2@v2.0.21/README.md (about) 1 # github.com/lestrrat-go/jwx/v2 ![](https://github.com/lestrrat-go/jwx/workflows/CI/badge.svg?branch=v2) [![Go Reference](https://pkg.go.dev/badge/github.com/lestrrat-go/jwx/v2.svg)](https://pkg.go.dev/github.com/lestrrat-go/jwx/v2) [![codecov.io](https://codecov.io/github/lestrrat-go/jwx/coverage.svg?branch=v2)](https://codecov.io/github/lestrrat-go/jwx?branch=v2) 2 3 Go module implementing various JWx (JWA/JWE/JWK/JWS/JWT, otherwise known as JOSE) technologies. 4 5 If you are using this module in your product or your company, please add your product and/or company name in the [Wiki](https://github.com/lestrrat-go/jwx/wiki/Users)! It really helps keeping up our motivation. 6 7 # Features 8 9 * Complete coverage of JWA/JWE/JWK/JWS/JWT, not just JWT+minimum tool set. 10 * Supports JWS messages with multiple signatures, both compact and JSON serialization 11 * Supports JWS with detached payload 12 * Supports JWS with unencoded payload (RFC7797) 13 * Supports JWE messages with multiple recipients, both compact and JSON serialization 14 * Most operations work with either JWK or raw keys e.g. *rsa.PrivateKey, *ecdsa.PrivateKey, etc). 15 * Opinionated, but very uniform API. Everything is symmetric, and follows a standard convention 16 * jws.Parse/Verify/Sign 17 * jwe.Parse/Encrypt/Decrypt 18 * Arguments are organized as explicit required paramters and optional WithXXXX() style options. 19 * Extra utilities 20 * `jwk.Cache` to always keep a JWKS up-to-date 21 * [bazel](https://bazel.build)-ready 22 23 Some more in-depth discussion on why you might want to use this library over others 24 can be found in the [Description section](#description) 25 26 If you are using v0 or v1, you are strongly encouraged to migrate to using v2 27 (the version that comes with the README you are reading). 28 29 # SYNOPSIS 30 31 <!-- INCLUDE(examples/jwx_readme_example_test.go) --> 32 ```go 33 package examples_test 34 35 import ( 36 "bytes" 37 "fmt" 38 "net/http" 39 "time" 40 41 "github.com/lestrrat-go/jwx/v2/jwa" 42 "github.com/lestrrat-go/jwx/v2/jwe" 43 "github.com/lestrrat-go/jwx/v2/jwk" 44 "github.com/lestrrat-go/jwx/v2/jws" 45 "github.com/lestrrat-go/jwx/v2/jwt" 46 ) 47 48 func ExampleJWX() { 49 // Parse, serialize, slice and dice JWKs! 50 privkey, err := jwk.ParseKey(jsonRSAPrivateKey) 51 if err != nil { 52 fmt.Printf("failed to parse JWK: %s\n", err) 53 return 54 } 55 56 pubkey, err := jwk.PublicKeyOf(privkey) 57 if err != nil { 58 fmt.Printf("failed to get public key: %s\n", err) 59 return 60 } 61 62 // Work with JWTs! 63 { 64 // Build a JWT! 65 tok, err := jwt.NewBuilder(). 66 Issuer(`github.com/lestrrat-go/jwx`). 67 IssuedAt(time.Now()). 68 Build() 69 if err != nil { 70 fmt.Printf("failed to build token: %s\n", err) 71 return 72 } 73 74 // Sign a JWT! 75 signed, err := jwt.Sign(tok, jwt.WithKey(jwa.RS256, privkey)) 76 if err != nil { 77 fmt.Printf("failed to sign token: %s\n", err) 78 return 79 } 80 81 // Verify a JWT! 82 { 83 verifiedToken, err := jwt.Parse(signed, jwt.WithKey(jwa.RS256, pubkey)) 84 if err != nil { 85 fmt.Printf("failed to verify JWS: %s\n", err) 86 return 87 } 88 _ = verifiedToken 89 } 90 91 // Work with *http.Request! 92 { 93 req, err := http.NewRequest(http.MethodGet, `https://github.com/lestrrat-go/jwx`, nil) 94 req.Header.Set(`Authorization`, fmt.Sprintf(`Bearer %s`, signed)) 95 96 verifiedToken, err := jwt.ParseRequest(req, jwt.WithKey(jwa.RS256, pubkey)) 97 if err != nil { 98 fmt.Printf("failed to verify token from HTTP request: %s\n", err) 99 return 100 } 101 _ = verifiedToken 102 } 103 } 104 105 // Encrypt and Decrypt arbitrary payload with JWE! 106 { 107 encrypted, err := jwe.Encrypt(payloadLoremIpsum, jwe.WithKey(jwa.RSA_OAEP, jwkRSAPublicKey)) 108 if err != nil { 109 fmt.Printf("failed to encrypt payload: %s\n", err) 110 return 111 } 112 113 decrypted, err := jwe.Decrypt(encrypted, jwe.WithKey(jwa.RSA_OAEP, jwkRSAPrivateKey)) 114 if err != nil { 115 fmt.Printf("failed to decrypt payload: %s\n", err) 116 return 117 } 118 119 if !bytes.Equal(decrypted, payloadLoremIpsum) { 120 fmt.Printf("verified payload did not match\n") 121 return 122 } 123 } 124 125 // Sign and Verify arbitrary payload with JWS! 126 { 127 signed, err := jws.Sign(payloadLoremIpsum, jws.WithKey(jwa.RS256, jwkRSAPrivateKey)) 128 if err != nil { 129 fmt.Printf("failed to sign payload: %s\n", err) 130 return 131 } 132 133 verified, err := jws.Verify(signed, jws.WithKey(jwa.RS256, jwkRSAPublicKey)) 134 if err != nil { 135 fmt.Printf("failed to verify payload: %s\n", err) 136 return 137 } 138 139 if !bytes.Equal(verified, payloadLoremIpsum) { 140 fmt.Printf("verified payload did not match\n") 141 return 142 } 143 } 144 // OUTPUT: 145 } 146 ``` 147 source: [examples/jwx_readme_example_test.go](https://github.com/lestrrat-go/jwx/blob/v2/examples/jwx_readme_example_test.go) 148 <!-- END INCLUDE --> 149 150 # How-to Documentation 151 152 * [API documentation](https://pkg.go.dev/github.com/lestrrat-go/jwx/v2) 153 * [How-to style documentation](./docs) 154 * [Runnable Examples](./examples) 155 156 # Description 157 158 This Go module implements JWA, JWE, JWK, JWS, and JWT. Please see the following table for the list of 159 available packages: 160 161 | Package name | Notes | 162 |-----------------------------------------------------------|-------------------------------------------------| 163 | [jwt](https://github.com/lestrrat-go/jwx/tree/v2/jwt) | [RFC 7519](https://tools.ietf.org/html/rfc7519) | 164 | [jwk](https://github.com/lestrrat-go/jwx/tree/v2/jwk) | [RFC 7517](https://tools.ietf.org/html/rfc7517) + [RFC 7638](https://tools.ietf.org/html/rfc7638) | 165 | [jwa](https://github.com/lestrrat-go/jwx/tree/v2/jwa) | [RFC 7518](https://tools.ietf.org/html/rfc7518) | 166 | [jws](https://github.com/lestrrat-go/jwx/tree/v2/jws) | [RFC 7515](https://tools.ietf.org/html/rfc7515) + [RFC 7797](https://tools.ietf.org/html/rfc7797) | 167 | [jwe](https://github.com/lestrrat-go/jwx/tree/v2/jwe) | [RFC 7516](https://tools.ietf.org/html/rfc7516) | 168 ## History 169 170 My goal was to write a server that heavily uses JWK and JWT. At first glance 171 the libraries that already exist seemed sufficient, but soon I realized that 172 173 1. To completely implement the protocols, I needed the entire JWT, JWK, JWS, JWE (and JWA, by necessity). 174 2. Most of the libraries that existed only deal with a subset of the various JWx specifications that were necessary to implement their specific needs 175 176 For example, a certain library looks like it had most of JWS, JWE, JWK covered, but then it lacked the ability to include private claims in its JWT responses. Another library had support of all the private claims, but completely lacked in its flexibility to generate various different response formats. 177 178 Because I was writing the server side (and the client side for testing), I needed the *entire* JOSE toolset to properly implement my server, **and** they needed to be *flexible* enough to fulfill the entire spec that I was writing. 179 180 So here's `github.com/lestrrat-go/jwx/v2`. This library is extensible, customizable, and hopefully well organized to the point that it is easy for you to slice and dice it. 181 182 ## Why would I use this library? 183 184 There are several other major Go modules that handle JWT and related data formats, 185 so why should you use this library? 186 187 From a purely functional perspective, the only major difference is this: 188 Whereas most other projects only deal with what they seem necessary to handle 189 JWTs, this module handles the **_entire_** spectrum of JWS, JWE, JWK, and JWT. 190 191 That is, if you need to not only parse JWTs, but also to control JWKs, or 192 if you need to handle payloads that are NOT JWTs, you should probably consider 193 using this module. You should also note that JWT is built _on top_ of those 194 other technologies. You simply cannot have a complete JWT package without 195 implementing the entirety of JWS/JWE/JWK, which this library does. 196 197 Next, from an implementation perspective, this module differs significantly 198 from others in that it tries very hard to expose only the APIs, and not the 199 internal data. For example, individual JWT claims are not accessible through 200 struct field lookups. You need to use one of the getter methods. 201 202 This is because this library takes the stance that the end user is fully capable 203 and even willing to shoot themselves on the foot when presented with a lax 204 API. By making sure that users do not have access to open structs, we can protect 205 users from doing silly things like creating _incomplete_ structs, or access the 206 structs concurrently without any protection. This structure also allows 207 us to put extra smarts in the structs, such as doing the right thing when 208 you want to parse / write custom fields (this module does not require the user 209 to specify alternate structs to parse objects with custom fields) 210 211 In the end I think it comes down to your usage pattern, and priorities. 212 Some general guidelines that come to mind are: 213 214 * If you want a single library to handle everything JWx, such as using JWE, JWK, JWS, handling [auto-refreshing JWKs](https://github.com/lestrrat-go/jwx/blob/v2/docs/04-jwk.md#auto-refreshing-remote-keys), use this module. 215 * If you want to honor all possible custom fields transparently, use this module. 216 * If you want a standardized clean API, use this module. 217 218 Otherwise, feel free to choose something else. 219 220 # Contributions 221 222 ## Issues 223 224 For bug reports and feature requests, please try to follow the issue templates as much as possible. 225 For either bug reports or feature requests, failing tests are even better. 226 227 ## Pull Requests 228 229 Please make sure to include tests that excercise the changes you made. 230 231 If you are editing auto-generated files (those files with the `_gen.go` suffix, please make sure that you do the following: 232 233 1. Edit the generator, not the generated files (e.g. internal/cmd/genreadfile/main.go) 234 2. Run `make generate` (or `go generate`) to generate the new code 235 3. Commit _both_ the generator _and_ the generated files 236 237 ## Discussions / Usage 238 239 Please try [discussions](https://github.com/lestrrat-go/jwx/tree/v2/discussions) first. 240 241 # Related Modules 242 243 * [github.com/lestrrat-go/echo-middileware-jwx](https://github.com/lestrrat-go/echo-middleware-jwx) - Sample Echo middleware 244 * [github.com/jwx-go/crypto-signer/gcp](https://github.com/jwx-go/crypto-signer/tree/main/gcp) - GCP KMS wrapper that implements [`crypto.Signer`](https://pkg.go.dev/crypto#Signer) 245 * [github.com/jwx-go/crypto-signer/aws](https://github.com/jwx-go/crypto-signer/tree/main/aws) - AWS KMS wrapper that implements [`crypto.Signer`](https://pkg.go.dev/crypto#Signer) 246 247 # Credits 248 249 * Initial work on this library was generously sponsored by HDE Inc (https://www.hde.co.jp) 250 * Lots of code, especially JWE was initially taken from go-jose library (https://github.com/square/go-jose) 251 * Lots of individual contributors have helped this project over the years. Thank each and everyone of you very much. 252