-
Notifications
You must be signed in to change notification settings - Fork 327
/
token_middleware.go
101 lines (84 loc) · 2.62 KB
/
token_middleware.go
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
package auth
import (
"context"
"fmt"
"net/http"
"github.com/cortezaproject/corteza/server/pkg/errors"
"github.com/go-chi/jwtauth"
"github.com/lestrrat-go/jwx/jwa"
"github.com/lestrrat-go/jwx/jwk"
"github.com/lestrrat-go/jwx/jwt"
)
var (
HttpTokenVerifier func(http.Handler) http.Handler
)
// verifier returns a jwt verification middleware
//
// Tasks
// 1. picks token from header, query or cookie
// 2. extracts identity (if any) and adds it into request context
//
// In there is no token
func verifier(ja *jwtauth.JWTAuth) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token, err := jwtauth.VerifyRequest(ja, r, jwtauth.TokenFromHeader, jwtauth.TokenFromQuery, jwtauth.TokenFromCookie)
ctx := r.Context()
if token != nil && err == nil {
if err = TokenIssuer.Validate(ctx, token); err != nil {
errors.ProperlyServeHTTP(w, r, err, false)
return
}
}
ctx = jwtauth.NewContext(ctx, token, err)
ctx = SetIdentityToContext(ctx, IdentityFromToken(token))
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
// TokenVerifierMiddlewareWithSecretSigner returns HTTP handler with simple jwa.HS512 + secret verifier
//
// This should be 1:1 with token issuer!
func TokenVerifierMiddlewareWithSecretSigner(secret string) (_ func(http.Handler) http.Handler, err error) {
if len(secret) == 0 {
return nil, fmt.Errorf("JWK missing")
}
var key jwk.Key
if key, err = jwk.New([]byte(secret)); err != nil {
return nil, fmt.Errorf("could not parse JWK: %w", err)
}
return verifier(jwtauth.New(jwa.HS512.String(), key, nil)), nil
}
// HttpTokenValidator checks if there is a token with identity and matching scope claim
//
// Empty scope defaults to "api"!
func HttpTokenValidator(scope ...string) func(http.Handler) http.Handler {
if len(scope) == 0 {
// ensure that scope is not empty
scope = []string{"api"}
}
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
err := verifyToken(r.Context(), scope...)
if err != nil && !errors.Is(err, jwtauth.ErrNoTokenFound) {
errors.ProperlyServeHTTP(w, r, err, false)
return
}
next.ServeHTTP(w, r)
})
}
}
// pulls token from context and validates scope & access-token
func verifyToken(ctx context.Context, scope ...string) (err error) {
var token jwt.Token
if token, _, err = jwtauth.FromContext(ctx); err != nil {
return
}
if token == nil {
return errUnauthorized()
}
if len(scope) > 0 && !CheckJwtScope(token, scope...) {
return errUnauthorizedScope()
}
return
}