Skip to content

Commit f47bf92

Browse files
committed
first pass at simplifying JWT library functionality into an interface (#77)
1 parent 4488b77 commit f47bf92

File tree

1 file changed

+16
-35
lines changed

1 file changed

+16
-35
lines changed

jwtmiddleware.go

Lines changed: 16 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ import (
77
"log"
88
"net/http"
99
"strings"
10-
11-
"github.com/form3tech-oss/jwt-go"
1210
)
1311

1412
// A function called whenever an error is encountered
@@ -21,18 +19,24 @@ type errorHandler func(w http.ResponseWriter, r *http.Request, err string)
2119
// be treated as an error. An empty string should be returned in that case.
2220
type TokenExtractor func(r *http.Request) (string, error)
2321

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+
2429
// Options is a struct for specifying configuration options for the middleware.
2530
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
3033
// The name of the property in the request where the user information
3134
// from the JWT will be stored.
3235
// Default value: "user"
3336
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
3640
ErrorHandler errorHandler
3741
// A boolean indicating if the credentials are required or not
3842
// Default value: false
@@ -46,11 +50,6 @@ type Options struct {
4650
// When set, all requests with the OPTIONS method will use authentication
4751
// Default: false
4852
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
5453
}
5554

5655
type JWTMiddleware struct {
@@ -200,37 +199,19 @@ func (m *JWTMiddleware) CheckJWT(w http.ResponseWriter, r *http.Request) error {
200199
return fmt.Errorf(errorMsg)
201200
}
202201

203-
// Now parse the token
204-
parsedToken, err := jwt.Parse(token, m.Options.ValidationKeyGetter)
202+
validToken, err := m.Options.Validate(token)
205203

206-
// Check if there was an error in parsing...
207204
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 {
224205
m.logf("Token is invalid")
225206
m.Options.ErrorHandler(w, r, "The token isn't valid")
226-
return errors.New("Token is invalid")
207+
return err
227208
}
228209

229-
m.logf("JWT: %v", parsedToken)
210+
m.logf("JWT: %v", validToken)
230211

231212
// If we get here, everything worked and we can set the
232213
// 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))
234215
// Update the current request with the new context information.
235216
*r = *newRequest
236217
return nil

0 commit comments

Comments
 (0)