diff --git a/jwtauth.go b/jwtauth.go index 1c4e268..ad3905b 100644 --- a/jwtauth.go +++ b/jwtauth.go @@ -106,7 +106,7 @@ func (ja *JwtAuth) Verify(paramAliases ...string) func(chi.Handler) chi.Handler // Verify the token token, err := ja.Decode(tokenStr) - if err != nil || !token.Valid || token.Method != ja.signer { + if err != nil { switch err.Error() { case "token is expired": err = ErrExpired @@ -117,6 +117,13 @@ func (ja *JwtAuth) Verify(paramAliases ...string) func(chi.Handler) chi.Handler return } + if !token.Valid || token.Method != ja.signer { + err = ErrUnauthorized + ctx = ja.SetContext(ctx, token, err) + next.ServeHTTPC(ctx, w, r) + return + } + // Check expiry via "exp" claim if ja.IsExpired(token) { err = ErrExpired diff --git a/jwtauth_test.go b/jwtauth_test.go index 42b3b33..3c04e49 100644 --- a/jwtauth_test.go +++ b/jwtauth_test.go @@ -54,6 +54,16 @@ func TestSimple(t *testing.T) { if status, resp := testRequest(t, ts, "GET", "/", h, nil); status != 401 && resp != "Unauthorized\n" { t.Fatalf(resp) } + // wrong token secret and wrong alg + h.Set("Authorization", "BEARER "+newJwt512Token([]byte("wrong"), map[string]interface{}{})) + if status, resp := testRequest(t, ts, "GET", "/", h, nil); status != 401 && resp != "Unauthorized\n" { + t.Fatalf(resp) + } + // correct token secret but wrong alg + h.Set("Authorization", "BEARER "+newJwt512Token(TokenSecret, map[string]interface{}{})) + if status, resp := testRequest(t, ts, "GET", "/", h, nil); status != 401 && resp != "Unauthorized\n" { + t.Fatalf(resp) + } // sending authorized requests if status, resp := testRequest(t, ts, "GET", "/", newAuthHeader(), nil); status != 200 && resp != "welcome" { @@ -127,6 +137,16 @@ func TestMore(t *testing.T) { if status, resp := testRequest(t, ts, "GET", "/admin", h, nil); status != 401 && resp != "Unauthorized\n" { t.Fatalf(resp) } + // wrong token secret and wrong alg + h.Set("Authorization", "BEARER "+newJwt512Token([]byte("wrong"), map[string]interface{}{})) + if status, resp := testRequest(t, ts, "GET", "/admin", h, nil); status != 401 && resp != "Unauthorized\n" { + t.Fatalf(resp) + } + // correct token secret but wrong alg + h.Set("Authorization", "BEARER "+newJwt512Token(TokenSecret, map[string]interface{}{})) + if status, resp := testRequest(t, ts, "GET", "/admin", h, nil); status != 401 && resp != "Unauthorized\n" { + t.Fatalf(resp) + } h = newAuthHeader((jwtauth.Claims{}).Set("exp", jwtauth.EpochNow()-1000)) if status, resp := testRequest(t, ts, "GET", "/admin", h, nil); status != 401 && resp != "expired\n" { @@ -191,6 +211,21 @@ func newJwtToken(secret []byte, claims ...jwtauth.Claims) string { return tokenStr } +func newJwt512Token(secret []byte, claims ...jwtauth.Claims) string { + // use-case: when token is signed with a different alg than expected + token := jwt.New(jwt.GetSigningMethod("HS512")) + if len(claims) > 0 { + for k, v := range claims[0] { + token.Claims[k] = v + } + } + tokenStr, err := token.SignedString(secret) + if err != nil { + log.Fatal(err) + } + return tokenStr +} + func newAuthHeader(claims ...jwtauth.Claims) http.Header { h := http.Header{} h.Set("Authorization", "BEARER "+newJwtToken(TokenSecret, claims...))