• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..03-May-2022-

buffer/H20-May-2019-213154

cmd/jwx/H20-May-2019-153127

internal/H20-May-2019-565445

jwa/H20-May-2019-715605

jwe/H20-May-2019-3,0542,425

jwk/H20-May-2019-3,0842,539

jws/H20-May-2019-3,1372,534

jwt/H20-May-2019-1,8881,565

scripts/H20-May-2019-3126

.gitignoreH A D20-May-2019311 3224

.travis.ymlH A D20-May-2019178 1312

LICENSEH A D20-May-20191.1 KiB2317

MakefileH A D20-May-2019321 1711

README.mdH A D20-May-20199.9 KiB296227

jwx.goH A D20-May-20191.1 KiB272

jwx_example_test.goH A D20-May-20192.6 KiB11792

README.md

1# jwx
2
3Implementation of various JWx technologies
4
5[![Build Status](https://travis-ci.org/lestrrat-go/jwx.svg?branch=master)](https://travis-ci.org/lestrrat-go/jwx)
6[![GoDoc](https://godoc.org/github.com/lestrrat-go/jwx?status.svg)](https://godoc.org/github.com/lestrrat-go/jwx)
7
8## Status
9
10### Done
11
12PR/issues welcome.
13
14| Package name                                              | Notes                                           |
15|-----------------------------------------------------------|-------------------------------------------------|
16| [jwt](https://github.com/lestrrat-go/jwx/tree/master/jwt) | [RFC 7519](https://tools.ietf.org/html/rfc7519) |
17| [jwk](https://github.com/lestrrat-go/jwx/tree/master/jwk) | [RFC 7517](https://tools.ietf.org/html/rfc7517) + [RFC 7638](https://tools.ietf.org/html/rfc7638) |
18| [jwa](https://github.com/lestrrat-go/jwx/tree/master/jwa) | [RFC 7518](https://tools.ietf.org/html/rfc7518) |
19| [jws](https://github.com/lestrrat-go/jwx/tree/master/jws) | [RFC 7515](https://tools.ietf.org/html/rfc7515) |
20| [jwe](https://github.com/lestrrat-go/jwx/tree/master/jwe) | [RFC 7516](https://tools.ietf.org/html/rfc7516) |
21
22### In progress:
23
24* jwe - more algorithms
25
26## Why?
27
28My goal was to write a server that heavily uses JWK and JWT. At first glance
29the libraries that already exist seemed sufficient, but soon I realized that
30
311. To completely implement the protocols, I needed the entire JWT, JWK, JWS, JWE (and JWA, by necessity).
322. Most of the libraries that existed only deal with a subset of the various JWx specifications that were necessary to implement their specific needs
33
34For 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.
35
36Because 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.
37
38So here's go-jwx. This library is extensible, customizable, and hopefully well organized to the point that it is easy for you to slice and dice it.
39
40As of this writing (Nov 2015), it's still lacking a few of the algorithms for JWE that are described in JWA (which I believe to be less frequently used), but in general you should be able to do pretty much everything allowed in the specifications.
41
42## Synopsis
43
44### JWT
45
46See the examples here as well: [https://github.com/lestrrat-go/jwx/jwt](./jwt/README.md)
47
48```go
49func ExampleJWT() {
50  const aLongLongTimeAgo = 233431200
51
52  t := jwt.New()
53  t.Set(jwt.SubjectKey, `https://github.com/lestrrat-go/jwx/jwt`)
54  t.Set(jwt.AudienceKey, `Golang Users`)
55  t.Set(jwt.IssuedAtKey, time.Unix(aLongLongTimeAgo, 0))
56  t.Set(`privateClaimKey`, `Hello, World!`)
57
58  buf, err := json.MarshalIndent(t, "", "  ")
59  if err != nil {
60    fmt.Printf("failed to generate JSON: %s\n", err)
61    return
62  }
63
64  fmt.Printf("%s\n", buf)
65  fmt.Printf("aud -> '%s'\n", t.Audience())
66  fmt.Printf("iat -> '%s'\n", t.IssuedAt().Format(time.RFC3339))
67  if v, ok := t.Get(`privateClaimKey`); ok {
68    fmt.Printf("privateClaimKey -> '%s'\n", v)
69  }
70  fmt.Printf("sub -> '%s'\n", t.Subject())
71}
72```
73
74### JWK
75
76See the examples here as well: https://godoc.org/github.com/lestrrat-go/jwx/jwk#pkg-examples
77
78Create a JWK file from RSA public key:
79
80```go
81import(
82  "crypto/rand"
83  "crypto/rsa"
84  "encoding/json"
85  "log"
86  "os"
87
88  "github.com/lestrrat-go/jwx/jwk"
89)
90
91func main() {
92  privkey, err := rsa.GenerateKey(rand.Reader, 2048)
93  if err != nil {
94    log.Printf("failed to generate private key: %s", err)
95    return
96  }
97
98  key, err := jwk.New(&privkey.PublicKey)
99  if err != nil {
100    log.Printf("failed to create JWK: %s", err)
101    return
102  }
103
104  jsonbuf, err := json.MarshalIndent(key, "", "  ")
105  if err != nil {
106    log.Printf("failed to generate JSON: %s", err)
107    return
108  }
109
110  os.Stdout.Write(jsonbuf)
111}
112```
113
114Parse and use a JWK key:
115
116```go
117import(
118  "log"
119
120  "github.com/lestrrat-go/jwx/jwk"
121)
122
123func main() {
124  set, err := jwk.Fetch("https://foobar.domain/jwk.json")
125  if err != nil {
126    log.Printf("failed to parse JWK: %s", err)
127    return
128  }
129
130  // If you KNOW you have exactly one key, you can just
131  // use set.Keys[0]
132  keys := set.LookupKeyID("mykey")
133  if len(keys) == 0 {
134    log.Printf("failed to lookup key: %s", err)
135    return
136  }
137
138  key, err := keys[0].Materialize()
139  if err != nil {
140    log.Printf("failed to create public key: %s", err)
141    return
142  }
143
144  // Use key for jws.Verify() or whatever
145}
146```
147
148### JWS
149
150See also `VerifyWithJWK` and `VerifyWithJKU`
151
152```go
153import(
154  "crypto/rand"
155  "crypto/rsa"
156  "log"
157
158  "github.com/lestrrat-go/jwx/jwa"
159  "github.com/lestrrat-go/jwx/jws"
160)
161
162func main() {
163  privkey, err := rsa.GenerateKey(rand.Reader, 2048)
164  if err != nil {
165    log.Printf("failed to generate private key: %s", err)
166    return
167  }
168
169  buf, err := jws.Sign([]byte("Lorem ipsum"), jwa.RS256, privkey)
170  if err != nil {
171    log.Printf("failed to created JWS message: %s", err)
172    return
173  }
174
175  // When you received a JWS message, you can verify the signature
176  // and grab the payload sent in the message in one go:
177  verified, err := jws.Verify(buf, jwa.RS256, &privkey.PublicKey)
178  if err != nil {
179    log.Printf("failed to verify message: %s", err)
180    return
181  }
182
183  log.Printf("signed message verified! -> %s", verified)
184}
185```
186
187Supported signature algorithms:
188
189| Algorithm                               | Supported? | Constant in go-jwx |
190|:----------------------------------------|:-----------|:-------------------|
191| HMAC using SHA-256                      | YES        | jwa.HS256          |
192| HMAC using SHA-384                      | YES        | jwa.HS384          |
193| HMAC using SHA-512                      | YES        | jwa.HS512          |
194| RSASSA-PKCS-v1.5 using SHA-256          | YES        | jwa.RS256          |
195| RSASSA-PKCS-v1.5 using SHA-384          | YES        | jwa.RS384          |
196| RSASSA-PKCS-v1.5 using SHA-512          | YES        | jwa.RS512          |
197| ECDSA using P-256 and SHA-256           | YES        | jwa.ES256          |
198| ECDSA using P-384 and SHA-384           | YES        | jwa.ES384          |
199| ECDSA using P-521 and SHA-512           | YES        | jwa.ES512          |
200| RSASSA-PSS using SHA256 and MGF1-SHA256 | YES        | jwa.PS256          |
201| RSASSA-PSS using SHA384 and MGF1-SHA384 | YES        | jwa.PS384          |
202| RSASSA-PSS using SHA512 and MGF1-SHA512 | YES        | jwa.PS512          |
203
204### JWE
205
206See the examples here as well: https://godoc.org/github.com/lestrrat-go/jwx/jwe#pkg-examples
207
208```go
209import(
210  "crypto/rand"
211  "crypto/rsa"
212  "log"
213
214  "github.com/lestrrat-go/jwx/jwa"
215  "github.com/lestrrat-go/jwx/jwe"
216)
217
218func main() {
219  privkey, err := rsa.GenerateKey(rand.Reader, 2048)
220  if err != nil {
221    log.Printf("failed to generate private key: %s", err)
222    return
223  }
224
225  payload := []byte("Lorem Ipsum")
226
227  encrypted, err := jwe.Encrypt(payload, jwa.RSA1_5, &privkey.PublicKey, jwa.A128CBC_HS256, jwa.NoCompress)
228  if err != nil {
229    log.Printf("failed to encrypt payload: %s", err)
230    return
231  }
232
233  decrypted, err := jwe.Decrypt(encrypted, jwa.RSA1_5, privkey)
234  if err != nil {
235    log.Printf("failed to decrypt: %s", err)
236    return
237  }
238
239  if string(decrypted) != "Lorem Ipsum" {
240    log.Printf("WHAT?!")
241    return
242  }
243}
244```
245
246Supported key encryption algorithm:
247
248| Algorithm                                | Supported? | Constant in go-jwx     |
249|:-----------------------------------------|:-----------|:-----------------------|
250| RSA-PKCS1v1.5                            | YES        | jwa.RSA1_5             |
251| RSA-OAEP-SHA1                            | YES        | jwa.RSA_OAEP           |
252| RSA-OAEP-SHA256                          | YES        | jwa.RSA_OAEP_256       |
253| AES key wrap (128)                       | YES        | jwa.A128KW             |
254| AES key wrap (192)                       | YES        | jwa.A192KW             |
255| AES key wrap (256)                       | YES        | jwa.A256KW             |
256| Direct encryption                        | NO         | jwa.DIRECT             |
257| ECDH-ES                                  | YES        | jwa.ECDH_ES            |
258| ECDH-ES + AES key wrap (128)             | YES        | jwa.ECDH_ES_A128KW     |
259| ECDH-ES + AES key wrap (192)             | YES        | jwa.ECDH_ES_A192KW     |
260| ECDH-ES + AES key wrap (256)             | YES        | jwa.ECDH_ES_A256KW     |
261| AES-GCM key wrap (128)                   | NO         | jwa.A128GCMKW          |
262| AES-GCM key wrap (192)                   | NO         | jwa.A192GCMKW          |
263| AES-GCM key wrap (256)                   | NO         | jwa.A256GCMKW          |
264| PBES2 + HMAC-SHA256 + AES key wrap (128) | NO         | jwa.PBES2_HS256_A128KW |
265| PBES2 + HMAC-SHA384 + AES key wrap (192) | NO         | jwa.PBES2_HS384_A192KW |
266| PBES2 + HMAC-SHA512 + AES key wrap (256) | NO         | jwa.PBES2_HS512_A256KW |
267
268Supported content encryption algorithm:
269
270| Algorithm                   | Supported? | Constant in go-jwx     |
271|:----------------------------|:-----------|:-----------------------|
272| AES-CBC + HMAC-SHA256 (128) | YES        | jwa.A128CBC_HS256      |
273| AES-CBC + HMAC-SHA384 (192) | YES        | jwa.A192CBC_HS384      |
274| AES-CBC + HMAC-SHA512 (256) | YES        | jwa.A256CBC_HS512      |
275| AES-GCM (128)               | YES        | jwa.A128GCM            |
276| AES-GCM (192)               | YES        | jwa.A192GCM            |
277| AES-GCM (256)               | YES        | jwa.A256GCM            |
278
279PRs welcome to support missing algorithms!
280
281## Other related libraries:
282
283* https://github.com/dgrijalva/jwt-go
284* https://github.com/square/go-jose
285* https://github.com/coreos/oidc
286* https://golang.org/x/oauth2
287
288## Contributions
289
290PRs welcome!
291
292## Credits
293
294* Work on this library was generously sponsored by HDE Inc (https://www.hde.co.jp)
295* Lots of code, especially JWE was taken from go-jose library (https://github.com/square/go-jose)
296