Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow JWT middleware to gracefully fail #2048

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions middleware/jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ type (
// ErrorHandlerWithContext is almost identical to ErrorHandler, but it's passed the current context.
ErrorHandlerWithContext JWTErrorHandlerWithContext

// A boolean indicating if the credentials are required or not
// Default value: false
CredentialsOptional bool

// Signing key to validate token.
// This is one of the three options to provide a token validation key.
// The order of precedence is a user-defined KeyFunc, SigningKeys and SigningKey.
Expand Down Expand Up @@ -218,6 +222,10 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
}
// If none of extractor has a token, handle error
if err != nil {
if config.CredentialsOptional {
return next(c)
}

if config.ErrorHandler != nil {
return config.ErrorHandler(err)
}
Expand All @@ -237,6 +245,9 @@ func JWTWithConfig(config JWTConfig) echo.MiddlewareFunc {
}
return next(c)
}
if config.CredentialsOptional {
return next(c)
}
if config.ErrorHandler != nil {
return config.ErrorHandler(err)
}
Expand Down
50 changes: 33 additions & 17 deletions middleware/jwt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,15 @@ func TestJWT(t *testing.T) {
validAuth := DefaultJWTConfig.AuthScheme + " " + token

for _, tc := range []struct {
expPanic bool
expErrCode int // 0 for Success
config JWTConfig
reqURL string // "/" if empty
hdrAuth string
hdrCookie string // test.Request doesn't provide SetCookie(); use name=val
formValues map[string]string
info string
expPanic bool
expErrCode int // 0 for Success
expEmptyCtx bool
config JWTConfig
reqURL string // "/" if empty
hdrAuth string
hdrCookie string // test.Request doesn't provide SetCookie(); use name=val
formValues map[string]string
info string
}{
{
expPanic: true,
Expand Down Expand Up @@ -266,6 +267,17 @@ func TestJWT(t *testing.T) {
config: JWTConfig{SigningKey: validKey},
info: "Valid JWT with lower case AuthScheme",
},
{
expEmptyCtx: true,
config: JWTConfig{SigningKey: validKey, CredentialsOptional: true},
info: "Valid JWT",
},
{
expEmptyCtx: false,
hdrAuth: validAuth,
config: JWTConfig{SigningKey: validKey, CredentialsOptional: true},
info: "Valid JWT",
},
} {
if tc.reqURL == "" {
tc.reqURL = "/"
Expand Down Expand Up @@ -309,15 +321,19 @@ func TestJWT(t *testing.T) {

h := JWTWithConfig(tc.config)(handler)
if assert.NoError(t, h(c), tc.info) {
user := c.Get("user").(*jwt.Token)
switch claims := user.Claims.(type) {
case jwt.MapClaims:
assert.Equal(t, claims["name"], "John Doe", tc.info)
case *jwtCustomClaims:
assert.Equal(t, claims.Name, "John Doe", tc.info)
assert.Equal(t, claims.Admin, true, tc.info)
default:
panic("unexpected type of claims")
if tc.expEmptyCtx {
assert.Nil(t, c.Get("user"), tc.info)
} else {
user := c.Get("user").(*jwt.Token)
switch claims := user.Claims.(type) {
case jwt.MapClaims:
assert.Equal(t, claims["name"], "John Doe", tc.info)
case *jwtCustomClaims:
assert.Equal(t, claims.Name, "John Doe", tc.info)
assert.Equal(t, claims.Admin, true, tc.info)
default:
panic("unexpected type of claims")
}
}
}
}
Expand Down