forked from pascaldekloe/jwt
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexamples_test.go
More file actions
264 lines (236 loc) · 7.72 KB
/
examples_test.go
File metadata and controls
264 lines (236 loc) · 7.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
package jwt_test
import (
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rand"
"crypto/rsa"
"fmt"
"io"
"net/http"
"net/http/httptest"
"os"
"time"
"github.com/pascaldekloe/jwt"
)
var someECKey *ecdsa.PrivateKey
var someRSAKey *rsa.PrivateKey
func init() {
var err error
someECKey, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
if err != nil {
panic(err)
}
someRSAKey, err = rsa.GenerateKey(rand.Reader, 1024)
if err != nil {
panic(err)
}
}
// Claims With The Standard HTTP Library
func Example() {
publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
fmt.Println("key generation error:", err)
return
}
// standard HTTP handler
http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) {
fmt.Fprintf(w, "Hello %s!\n", req.Header.Get("X-Verified-Name"))
fmt.Fprintf(w, "You are authorized as %s.\n", req.Header.Get("X-Verified-User"))
})
// secure service configuration
srv := httptest.NewTLSServer(&jwt.Handler{
Target: http.DefaultServeMux,
Keys: &jwt.KeyRegister{EdDSAs: []ed25519.PublicKey{publicKey}},
HeaderPrefix: "X-Verified-",
HeaderBinding: map[string]string{
"sub": "X-Verified-User", // registered [standard] claim name
"fn": "X-Verified-Name", // private [custom] claim name
},
})
defer srv.Close()
// self-signed request
var claims jwt.Claims
claims.Subject = "lakane"
claims.Set = map[string]interface{}{
"fn": "Lana Anthony Kane",
}
req, _ := http.NewRequest("GET", srv.URL, nil)
if err := claims.EdDSASignHeader(req, privateKey); err != nil {
fmt.Println("sign error:", err)
}
// call service
resp, _ := srv.Client().Do(req)
fmt.Println("HTTP", resp.Status)
io.Copy(os.Stdout, resp.Body)
// Output: HTTP 200 OK
// Hello Lana Anthony Kane!
// You are authorized as lakane.
}
// Typed Claim Lookups
func ExampleClaims_byName() {
offset := time.Unix(1537622794, 0)
c := jwt.Claims{
Registered: jwt.Registered{
Issuer: "a",
Subject: "b",
Audiences: []string{"c"},
Expires: jwt.NewNumericTime(offset.Add(time.Minute)),
NotBefore: jwt.NewNumericTime(offset.Add(-time.Second)),
Issued: jwt.NewNumericTime(offset),
ID: "d",
},
}
for _, name := range []string{"iss", "sub", "aud", "exp", "nbf", "iat", "jti"} {
if s, ok := c.String(name); ok {
fmt.Printf("%q: %q\n", name, s)
}
if n, ok := c.Number(name); ok {
fmt.Printf("%q: %0.f\n", name, n)
}
}
// Output:
// "iss": "a"
// "sub": "b"
// "aud": "c"
// "exp": 1537622854
// "nbf": 1537622793
// "iat": 1537622794
// "jti": "d"
}
// Full Access To The JWT Claims
func ExampleHandler_context() {
h := &jwt.Handler{
Target: http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
claims := req.Context().Value("verified-jwt").(*jwt.Claims)
if n, ok := claims.Number("deadline"); !ok {
fmt.Fprintln(w, "no deadline")
} else {
t := jwt.NumericTime(n)
fmt.Fprintln(w, "deadline at", t.String())
}
}),
Keys: &jwt.KeyRegister{Secrets: [][]byte{[]byte("killarcherdie")}},
ContextKey: "verified-jwt",
}
req := httptest.NewRequest("GET", "/status", nil)
req.Header.Set("Authorization", "Bearer eyJhbGciOiJIUzI1NiJ9.eyJkZWFkbGluZSI6NjcxNTAwNzk5fQ.yeUUNOj4-RvNp5Lt0d3lpS7MTgsS_Uk9XnsXJ3kVLhw")
resp := httptest.NewRecorder()
h.ServeHTTP(resp, req)
fmt.Println("HTTP", resp.Code)
fmt.Println(resp.Body)
// Output: HTTP 200
// deadline at 1991-04-12T23:59:59Z
}
// Standard Compliant Security Out-of-the-box
func ExampleHandler_deny() {
h := &jwt.Handler{
Target: http.HandlerFunc(func(http.ResponseWriter, *http.Request) {
panic("reached target handler")
}),
Keys: &jwt.KeyRegister{ECDSAs: []*ecdsa.PublicKey{&someECKey.PublicKey}},
Func: func(w http.ResponseWriter, req *http.Request, claims *jwt.Claims) (pass bool) {
panic("reached JWT-enhanced handler")
},
}
req := httptest.NewRequest("GET", "/had-something-for-this", nil)
fmt.Print("Try without authorization… ")
resp := httptest.NewRecorder()
h.ServeHTTP(resp, req)
fmt.Println("HTTP", resp.Code, resp.Header().Get("WWW-Authenticate"))
fmt.Print("Try another algorithm… ")
var c jwt.Claims
if err := c.HMACSignHeader(req, jwt.HS512, []byte("guest")); err != nil {
fmt.Println("sign error:", err)
}
resp = httptest.NewRecorder()
h.ServeHTTP(resp, req)
fmt.Println("HTTP", resp.Code, resp.Header().Get("WWW-Authenticate"))
fmt.Print("Try expired token… ")
c.Expires = jwt.NewNumericTime(time.Now().Add(-time.Second))
if err := c.ECDSASignHeader(req, jwt.ES512, someECKey); err != nil {
fmt.Println("sign error:", err)
}
resp = httptest.NewRecorder()
h.ServeHTTP(resp, req)
fmt.Println("HTTP", resp.Code, resp.Header().Get("WWW-Authenticate"))
// Output:
// Try without authorization… HTTP 401 Bearer
// Try another algorithm… HTTP 401 Bearer error="invalid_token", error_description="jwt: signature mismatch"
// Try expired token… HTTP 401 Bearer error="invalid_token", error_description="jwt: time constraints exceeded"
}
// Func As A Request Filter
func ExampleHandler_filter() {
h := &jwt.Handler{
Target: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Elaborate voicemail hoax!"))
}),
Keys: &jwt.KeyRegister{RSAs: []*rsa.PublicKey{&someRSAKey.PublicKey}},
Func: func(w http.ResponseWriter, req *http.Request, claims *jwt.Claims) (pass bool) {
if claims.Subject != "marcher" {
http.Error(w, "Ring, ring!", http.StatusServiceUnavailable)
return false
}
return true
},
}
// build request
req := httptest.NewRequest("GET", "/urgent", nil)
if err := new(jwt.Claims).RSASignHeader(req, jwt.PS512, someRSAKey); err != nil {
fmt.Println("sign error:", err)
}
// get response
resp := httptest.NewRecorder()
h.ServeHTTP(resp, req)
fmt.Println("HTTP", resp.Code, resp.Body)
// Output: HTTP 503 Ring, ring!
}
// PEM With Password Protection
func ExampleKeyRegister_LoadPEM_encrypted() {
const pem = `Keep it private! ✨
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: AES-128-CBC,65789712555A3E9FECD1D5E235B97B0C
o0Dz8S6QjGVq59yQdlakuKkoO0jKDN0PDu2L05ZLXwBQSGdIbRXtAOBRCNEME0V1
IF9pM6uRU7tqFoVneNTHD3XySJG8AHrTPSKC3Xw31pjEolMfoNDBAu1bYR6XxM2X
oDu2UNVB9vd/3b4bwTH9q5ISWdCVhS/ky0lC9lHXman/F/7MsemiVVCQ4XTIi9CR
nitMxJuXvkNBMtsyv+inmFMegKU6dj1DU93B9JpsFRRvy3TCfj9kRjhKWEpyindo
yaZMH3EGOA3ALW5kWyr+XegyYznQbVdDlo/ikO9BAywBOx+DdRG4xYxRdxYt8/HH
qXwPAGQe2veMlR7Iq3GjwHLebyuVc+iHbC7feRmNBpAT1RR7J+RIGlDPOBMUpuDT
A8HbNzPkoXPGh9vMsREXtR5aPCaZISdcm8DTlNiZCPaX5VHL4SRJ5XjI2rnahaOE
rhCFy0mxqQaKnEI9kCWWFmhX/MqzzfiW3yg0qFIAVLDQZZMFJr3jMHIvkxPk09rP
nQIjMRBalFXmSiksx8UEhAzyriqiXwwgEI0gJVHcs3EIQGD5jNqvIYTX67/rqSF2
OXoYuq0MHrAJgEfDncXvZFFMuAS/5KMvzSXfWr5/L0ncCU9UykjdPrFvetG/7IXQ
BT1TX4pOeW15a6fg6KwSZ5KPrt3o8qtRfW4Ov49hPD2EhnCTMbkCRBbW8F13+9YF
xzvC4Vm1r/Oa4TTUbf5tVto7ua/lZvwnu5DIWn2zy5ZUPrtn22r1ymVui7Iuhl0b
SRcADdHh3NgrjDjalhLDB95ho5omG39l7qBKBTlBAYJhDuAk9rIk1FCfCB8upztt
-----END RSA PRIVATE KEY-----`
var keys jwt.KeyRegister
n, err := keys.LoadPEM([]byte(pem), []byte("dangerzone"))
if err != nil {
fmt.Println("load error:", err)
}
fmt.Println(n, "keys added")
// Output: 1 keys added
}
// JWKS With Key IDs
func ExampleKeyRegister_LoadJWK() {
const json = `{
"keys": [
{"kty": "OKP", "crv":"Ed25519", "kid": "kazak",
"d":"nWGxne_9WmC6hEr0kuwsxERJxWl7MmkZcDusAxyuf2A",
"x":"11qYAYKxCrfVS_7TyWQHOg7hcvPapiMlrwIaaPcHURo"},
{"kty":"oct", "k":"a29mdGE", "kid": "good old"}
]
}`
var keys jwt.KeyRegister
n, err := keys.LoadJWK([]byte(json))
if err != nil {
fmt.Println("load error:", err)
}
fmt.Printf("%d keys added: ", n)
fmt.Printf("%d EdDSA %s & ", len(keys.EdDSAs), keys.EdDSAIDs)
fmt.Printf("%d secret %s: %s", len(keys.Secrets), keys.SecretIDs, keys.Secrets)
// Output:
// 2 keys added: 1 EdDSA [kazak] & 1 secret [good old]: [kofta]
}