1# Working with JWS
2
3In this document we describe how to work with JWS using [`github.com/lestrrat-go/jwx/jws`](https://pkg.go.dev/github.com/lestrrat-go/jwx/jws)
4
5* [Parsing](#parsing)
6 * [Getting the payload from a JWS encoded buffer](#getting-the-payload-from-a-jws-encoded-buffer)
7 * [Parse a JWS encoded buffer into a jws.Message](#parse-a-jws-encoded-buffer-into-a-jwsmessage)
8 * [Parse a JWS encoded message stored in a file](#parse-a-jws-encoded-message-stored-in-a-file)
9* [Signing](#signing)
10 * [Generating a JWS message in compact serialization format](#generating-a-jws-message-in-compact-serialization-format)
11 * [Generating a JWS message in JSON serialization format](#generating-a-jws-message-in-json-serialization-format)
12 * [Generating a JWS message with detached payload](#generating-a-jws-with-detached-payload)
13 * [Using cloud KMS services](#using-cloud-kms-services)
14* [Verifying](#verifying)
15 * [Verification using `jku`](#verification-using-jku)
16* [Using a custom signing/verification algorithm](#using-a-customg-signingverification-algorithm)
17* [Enabling ES256K](#enabling-es256k)
18# Parsing
19
20## Getting the payload from a JWS encoded buffer
21
22If you want to get the payload in the JWS message after it has been verified, use [`jws.Verify()`](https://pkg.go.dev/github.com/lestrrat-go/jwx/jws#Verify)
23
24```go
25var encoded = []byte{...}
26payload, _ := jws.Verify(encoded, alg, key)
27```
28
29You must provide the algorithm and the public key to use for verification.
30Please read "[Why don't you automatically infer the algorithm for `jws.Verify`?](99-faq.md#why-dont-you-automatically-infer-the-algorithm-for-jwsverify-)"
31
32If the algorithm or the key does not match, an error is returned.
33
34## Parse a JWS encoded buffer into a jws.Message
35
36You can parse a JWS buffer into a [`jws.Message`](https://pkg.go.dev/github.com/lestrrat-go/jwx/jws#Message) object. In this mode, there is no verification performed.
37
38```go
39var payload = []byte{...}
40msg, _ := jws.Parse(payload)
41```
42
43Note that [`jws.Message`](https://pkg.go.dev/github.com/lestrrat-go/jwx/jws#Message) is not really built for general signing/verification usage.
44It's built more so for inspection purposes.
45Think twice before attempting to do anything more than inspection using [`jws.Message`](https://pkg.go.dev/github.com/lestrrat-go/jwx/jws#Message).
46
47## Parse a JWS encoded message stored in a file
48
49To parse a JWS stored in a file, use [`jws.ReadFile()`](https://pkg.go.dev/github.com/lestrrat-go/jwx/jws#ReadFile). [`jws.ReadFile()`](https://pkg.go.dev/github.com/lestrrat-go/jwx/jws#ReadFile) accepts the same options as [`jws.Parse()`](https://pkg.go.dev/github.com/lestrrat-go/jwx/jws#Parse).
50
51```go
52message, _ := jws.ReadFile(`message.jws`)
53```
54
55## Verify a JWS with detached payload
56
57To parse a JWS with detached payload, use the `jws.WithDetachedPayload()` option:
58
59```go
60signed, _ := jws.Verify(signed, alg, key, jws.WithDetachedPayload(payload))
61```
62
63# Signing
64
65## Generating a JWS message in compact serialization format
66
67In most cases this is all you really need.
68
69```go
70signed, _ := jws.Sign(payload, alg, key)
71```
72
73To sign a JWT, use [`jwt.Sign()`](https://pkg.go.dev/github.com/lestrrat-go/jwx/jwt#Sign)
74
75```go
76signed, _ := jwt.Sign(token, alg, key)
77```
78
79## Generating a JWS message in JSON serialization format
80
81Generally the only time you need to use a JSON serialization format is when you have to generate multiple signatures for a given payload using multiple signing algorithms and keys.
82When this need arises, use the [`jws.SignMulti()`](https://pkg.go.dev/github.com/lestrrat-go/jwx/jws#SignMulti) method.
83
84```go
85signer, _ := jws.NewSigner(alg)
86signed, _ := jws.SignMulti(payload, jws.WithSigner(signer, key, pubHeaders, protHeaders)
87```
88
89## Generating a JWS message with detached payload
90
91Use the `jws.WithDetachedPayload()` option to sign a detached payload:
92
93```go
94signed, _ := jws.Sign(nil, alg, key, jws.WithDetachedPayload(payload))
95```
96
97## Including Arbitrary Headers to Compact Serialization
98
99By default, only some header fields are included in the result from `jws.Sign()`.
100If you want to include more headers fields in the resulting JWS, you will have to provide them via the `jws.WithHeaders()` option
101
102```go
103hdrs := jws.NewHeaders()
104hdrs.Set(`arbitrary-key`, `value`)
105signed, _ := jws.Sign(payload, alg, key, jws.WithHEaders(hdrs))
106```
107
108## Using cloud KMS services
109
110If you want to use cloud KMSes such as AWS KMS to sign and verify payloads, look for an object that implements
111`crypto.Signer`. There are some [implementations written for this module](https://github.com/jwx-go/crypto-signer).
112
113Event if you cannot find an implementation that you are looking for in the above repository, any other implementation that implements `crypto.Signer` should work.
114
115# Verifying
116
117## Verification using a single key
118
119Simply use `jws.Verify()`. It will automatically do the right thing whether it's serialized in compact
120form or JSON form.
121
122```go
123payload, _ := jws.Verify(data, alg, key)
124```
125
126The `alg` must be explicitly specified. See "[Why don't you automatically infer the algorithm for `jws.Verify`?](99-faq.md#why-dont-you-automatically-infer-the-algorithm-for-jwsverify-)"
127
128To verify a JWS message with detached payload, use the `jws.WithDetachedPayload()` option:
129
130```go
131_, err := jws.Verify(data, alg, key, jws.WithDetachedPayload(payload))
132```
133
134## Verification using `jku`
135
136Regular calls to `jws.Verify()` does not respect the JWK Set referenced in the `jku` field. In order to
137verify the payload using the `jku` field, you must use the `jws.VerifyAuto()` function.
138
139```go
140wl := ... // Create an appropriate whitelist
141payload, _ := jws.VerifyAuto(buf, jws.WithFetchWhitelist(wl))
142```
143
144This will tell `jws` to verify the given buffer using the JWK Set presented at the URL specified in
145the `jku` field. If the buffer is a JSON message, then this is done for each of the signature in
146the `signatures` array.
147
148The URL in the `jku` field must have the `https` scheme, and the key ID in the JWK Set must
149match the key ID present in the JWS message.
150
151Because this operation will result in your program accessing remote resources, the default behavior
152is to NOT allow any URLs. You must specify a whitelist
153
154```go
155wl := jwk.NewMapWhitelist().
156 Add(`https://white-listed-address`)
157
158payload, _ := jws.VerifyAuto(buf, jws.WithFetchWhitelist(wl))
159```
160
161If you want to allow any URLs to be accessible, use the `jwk.InsecureWhitelist`.
162
163```go
164wl := jwk.InsecureWhitelist{}
165payload, _ := jws.VerifyAuto(buf, jws.WithFetchWhitelist(wl))
166```
167
168If you must configure the HTTP Client in a special way, use the `jws.WithHTTPClient()` option:
169
170```go
171client := &http.Client{ ... }
172payload, _ := jws.VerifyAuto(buf, jws.WithHTTPClient(client))
173```
174
175# Using a custom signing/verification algorithm
176
177Sometimes we do not offer a particular algorithm out of the box, but you have an implementation for it.
178
179In such scenarios, you can use the [`jws.RegisterSigner()`](https://pkg.go.dev/github.com/lestrrat-go/jwx/jws#RegisterSigner) and [`jws.RegisterVerifier()`](https://pkg.go.dev/github.com/lestrrat-go/jwx/jws#RegisterVerifier) functions to
180generate your own verifier instance.
181
182```go
183jws.RegisterSigner(alg, signerFactory)
184jws.RegisterVerifier(alg, verifierFactory)
185```
186
187# Enabling ES256K
188
189See [Enabling Optional Signature Methods](./20-global-settings.md#enabling-optional-signature-methods)
View as plain text