7
7
"log"
8
8
"net/http"
9
9
"strings"
10
-
11
- "github.com/form3tech-oss/jwt-go"
12
10
)
13
11
14
12
// A function called whenever an error is encountered
@@ -21,18 +19,24 @@ type errorHandler func(w http.ResponseWriter, r *http.Request, err string)
21
19
// be treated as an error. An empty string should be returned in that case.
22
20
type TokenExtractor func (r * http.Request ) (string , error )
23
21
22
+ // ValidateToken takes in a string JWT and handles making sure it is valid and
23
+ // returning the valid token. If it is not valid it will return nil and an
24
+ // error message describing why validation failed.
25
+ // Inside of ValidateToken is where things like key and alg checking can
26
+ // happen. In the default implementation we can add safe defaults for those.
27
+ type ValidateToken func (string ) (interface {}, error )
28
+
24
29
// Options is a struct for specifying configuration options for the middleware.
25
30
type Options struct {
26
- // The function that will return the Key to validate the JWT.
27
- // It can be either a shared secret or a public key.
28
- // Default value: nil
29
- ValidationKeyGetter jwt.Keyfunc
31
+ // Validate handles validating a token.
32
+ Validate ValidateToken
30
33
// The name of the property in the request where the user information
31
34
// from the JWT will be stored.
32
35
// Default value: "user"
33
36
UserProperty string
34
- // The function that will be called when there's an error validating the token
35
- // Default value:
37
+ // The function that will be called when there are errors in the
38
+ // middleware.
39
+ // Default value: OnError
36
40
ErrorHandler errorHandler
37
41
// A boolean indicating if the credentials are required or not
38
42
// Default value: false
@@ -46,11 +50,6 @@ type Options struct {
46
50
// When set, all requests with the OPTIONS method will use authentication
47
51
// Default: false
48
52
EnableAuthOnOptions bool
49
- // When set, the middelware verifies that tokens are signed with the specific signing algorithm
50
- // If the signing method is not constant the ValidationKeyGetter callback can be used to implement additional checks
51
- // Important to avoid security issues described here: https://auth0.com/blog/critical-vulnerabilities-in-json-web-token-libraries/
52
- // Default: nil
53
- SigningMethod jwt.SigningMethod
54
53
}
55
54
56
55
type JWTMiddleware struct {
@@ -200,37 +199,19 @@ func (m *JWTMiddleware) CheckJWT(w http.ResponseWriter, r *http.Request) error {
200
199
return fmt .Errorf (errorMsg )
201
200
}
202
201
203
- // Now parse the token
204
- parsedToken , err := jwt .Parse (token , m .Options .ValidationKeyGetter )
202
+ validToken , err := m .Options .Validate (token )
205
203
206
- // Check if there was an error in parsing...
207
204
if err != nil {
208
- m .logf ("Error parsing token: %v" , err )
209
- m .Options .ErrorHandler (w , r , err .Error ())
210
- return fmt .Errorf ("Error parsing token: %w" , err )
211
- }
212
-
213
- if m .Options .SigningMethod != nil && m .Options .SigningMethod .Alg () != parsedToken .Header ["alg" ] {
214
- message := fmt .Sprintf ("Expected %s signing method but token specified %s" ,
215
- m .Options .SigningMethod .Alg (),
216
- parsedToken .Header ["alg" ])
217
- m .logf ("Error validating token algorithm: %s" , message )
218
- m .Options .ErrorHandler (w , r , errors .New (message ).Error ())
219
- return fmt .Errorf ("Error validating token algorithm: %s" , message )
220
- }
221
-
222
- // Check if the parsed token is valid...
223
- if ! parsedToken .Valid {
224
205
m .logf ("Token is invalid" )
225
206
m .Options .ErrorHandler (w , r , "The token isn't valid" )
226
- return errors . New ( "Token is invalid" )
207
+ return err
227
208
}
228
209
229
- m .logf ("JWT: %v" , parsedToken )
210
+ m .logf ("JWT: %v" , validToken )
230
211
231
212
// If we get here, everything worked and we can set the
232
213
// user property in context.
233
- newRequest := r .WithContext (context .WithValue (r .Context (), m .Options .UserProperty , parsedToken ))
214
+ newRequest := r .WithContext (context .WithValue (r .Context (), m .Options .UserProperty , validToken ))
234
215
// Update the current request with the new context information.
235
216
* r = * newRequest
236
217
return nil
0 commit comments