Skip to content
Merged
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
6 changes: 3 additions & 3 deletions .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,17 @@ permissions:

env:
# run static analysis only with the latest Go version
LATEST_GO_VERSION: "1.24"
LATEST_GO_VERSION: "1.25"

jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v4
uses: actions/checkout@v5

- name: Set up Go ${{ matrix.go }}
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: ${{ env.LATEST_GO_VERSION }}
check-latest: true
Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/echo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ permissions:

env:
# run coverage and benchmarks only with the latest Go version
LATEST_GO_VERSION: "1.24"
LATEST_GO_VERSION: "1.25"

jobs:
test:
Expand All @@ -25,15 +25,15 @@ jobs:
# Echo tests with last four major releases (unless there are pressing vulnerabilities)
# As we depend on `golang.org/x/` libraries which only support last 2 Go releases we could have situations when
# we derive from last four major releases promise.
go: ["1.23", "1.24"]
go: ["1.24", "1.25"]
name: ${{ matrix.os }} @ Go ${{ matrix.go }}
runs-on: ${{ matrix.os }}
steps:
- name: Checkout Code
uses: actions/checkout@v4
uses: actions/checkout@v5

- name: Set up Go ${{ matrix.go }}
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go }}

Expand All @@ -42,7 +42,7 @@ jobs:

- name: Upload coverage to Codecov
if: success() && matrix.go == env.LATEST_GO_VERSION && matrix.os == 'ubuntu-latest'
uses: codecov/codecov-action@v3
uses: codecov/codecov-action@v5
with:
token:
fail_ci_if_error: false
Expand All @@ -59,12 +59,12 @@ jobs:
path: previous

- name: Checkout Code (New)
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
path: new

- name: Set up Go ${{ matrix.go }}
uses: actions/setup-go@v5
uses: actions/setup-go@v6
with:
go-version: ${{ env.LATEST_GO_VERSION }}

Expand Down
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## v4.4.0 - 2025-11-20

**Enhancements**

* Revert 'Return HTTP status 400 if missing JWT' PR to return 401 [#39](https://github.com/labstack/echo-jwt/pull/39)
* Updated dependencies [#39](https://github.com/labstack/echo-jwt/pull/39)
* Return ErrJWTMissing, ErrJWTInvalid clones so error code could be changed more easily


## v4.3.1 - 2025-03-22

**Security**
Expand Down
18 changes: 9 additions & 9 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
module github.com/labstack/echo-jwt/v4

go 1.23.0
go 1.24.0

require (
github.com/golang-jwt/jwt/v5 v5.2.2
github.com/labstack/echo/v4 v4.13.3
github.com/stretchr/testify v1.10.0
github.com/golang-jwt/jwt/v5 v5.3.0
github.com/labstack/echo/v4 v4.13.4
github.com/stretchr/testify v1.11.1
)

require (
Expand All @@ -16,10 +16,10 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
golang.org/x/crypto v0.36.0 // indirect
golang.org/x/net v0.37.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
golang.org/x/time v0.11.0 // indirect
golang.org/x/crypto v0.45.0 // indirect
golang.org/x/net v0.47.0 // indirect
golang.org/x/sys v0.38.0 // indirect
golang.org/x/text v0.31.0 // indirect
golang.org/x/time v0.14.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)
30 changes: 16 additions & 14 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8=
github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/labstack/echo/v4 v4.13.3 h1:pwhpCPrTl5qry5HRdM5FwdXnhXSLSY+WE+YQSeCaafY=
github.com/labstack/echo/v4 v4.13.3/go.mod h1:o90YNEeQWjDozo584l7AwhJMHN0bOC4tAfg+Xox9q5g=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/labstack/echo/v4 v4.13.4 h1:oTZZW+T3s9gAu5L8vmzihV7/lkXGZuITzTQkTEhcXEA=
github.com/labstack/echo/v4 v4.13.4/go.mod h1:g63b33BZ5vZzcIUF8AtRH40DrTlXnx4UMC8rBdndmjQ=
github.com/labstack/gommon v0.4.2 h1:F8qTUNXgG1+6WQmqoUWnz8WiEU60mXVVw0P4ht1WRA0=
github.com/labstack/gommon v0.4.2/go.mod h1:QlUFxVM+SNXhDL/Z7YhocGIBYOiwB0mXm1+1bAPHPyU=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
Expand All @@ -14,21 +14,23 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
golang.org/x/crypto v0.36.0 h1:AnAEvhDddvBdpY+uR+MyHmuZzzNqXSe/GvuDeob5L34=
golang.org/x/crypto v0.36.0/go.mod h1:Y4J0ReaxCR1IMaabaSMugxJES1EpwhBHhv2bDHklZvc=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q=
golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4=
golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY=
golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/time v0.11.0 h1:/bpjEDfN9tkoN/ryeYHnv5hcMlc8ncjMcM4XBk5NWV0=
golang.org/x/time v0.11.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg=
golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc=
golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM=
golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM=
golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI=
golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down
10 changes: 4 additions & 6 deletions jwt.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,7 @@ func (e *TokenError) Unwrap() error { return e.Err }
// JWT returns a JSON Web Token (JWT) auth middleware.
//
// For valid token, it sets the user in context and calls next handler.
// For invalid token, it returns "401 - Unauthorized" error.
// For missing token, it returns "400 - Bad Request" error.
// For invalid or missing token, middleware returns "401 - Unauthorized" error.
//
// See: https://jwt.io/introduction
func JWT(signingKey interface{}) echo.MiddlewareFunc {
Expand All @@ -157,8 +156,7 @@ func JWT(signingKey interface{}) echo.MiddlewareFunc {
// WithConfig returns a JSON Web Token (JWT) auth middleware or panics if configuration is invalid.
//
// For valid token, it sets the user in context and calls next handler.
// For invalid token, it returns "401 - Unauthorized" error.
// For missing token, it returns "400 - Bad Request" error.
// For invalid or missing token, middleware returns "401 - Unauthorized" error.
//
// See: https://jwt.io/introduction
func WithConfig(config Config) echo.MiddlewareFunc {
Expand Down Expand Up @@ -255,10 +253,10 @@ func (config Config) ToMiddleware() (echo.MiddlewareFunc, error) {
}

if lastTokenErr == nil {
return echo.NewHTTPError(http.StatusBadRequest, "missing or malformed jwt").SetInternal(err)
return ErrJWTMissing.WithInternal(err)
}

return echo.NewHTTPError(http.StatusUnauthorized, "invalid or expired jwt").SetInternal(err)
return ErrJWTInvalid.WithInternal(err)
}
}, nil
}
Expand Down
12 changes: 6 additions & 6 deletions jwt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,14 +156,14 @@ func TestJWT_combinations(t *testing.T) {
config: Config{
SigningKey: validKey,
},
expectError: "code=400, message=missing or malformed jwt, internal=invalid value in request header",
expectError: "code=401, message=missing or malformed jwt, internal=invalid value in request header",
},
{
name: "Empty header auth field",
config: Config{
SigningKey: validKey,
},
expectError: "code=400, message=missing or malformed jwt, internal=invalid value in request header",
expectError: "code=401, message=missing or malformed jwt, internal=invalid value in request header",
},
{
name: "Valid query method",
Expand All @@ -180,7 +180,7 @@ func TestJWT_combinations(t *testing.T) {
TokenLookup: "query:jwt",
},
reqURL: "/?a=b&jwtxyz=" + token,
expectError: "code=400, message=missing or malformed jwt, internal=missing value in the query string",
expectError: "code=401, message=missing or malformed jwt, internal=missing value in the query string",
},
{
name: "Invalid query param value",
Expand All @@ -198,7 +198,7 @@ func TestJWT_combinations(t *testing.T) {
TokenLookup: "query:jwt",
},
reqURL: "/?a=b",
expectError: "code=400, message=missing or malformed jwt, internal=missing value in the query string",
expectError: "code=401, message=missing or malformed jwt, internal=missing value in the query string",
},
{
config: Config{
Expand Down Expand Up @@ -239,7 +239,7 @@ func TestJWT_combinations(t *testing.T) {
SigningKey: validKey,
TokenLookup: "cookie:jwt",
},
expectError: "code=400, message=missing or malformed jwt, internal=missing value in cookies",
expectError: "code=401, message=missing or malformed jwt, internal=missing value in cookies",
},
{
name: "Valid form method",
Expand All @@ -264,7 +264,7 @@ func TestJWT_combinations(t *testing.T) {
SigningKey: validKey,
TokenLookup: "form:jwt",
},
expectError: "code=400, message=missing or malformed jwt, internal=missing value in the form",
expectError: "code=401, message=missing or malformed jwt, internal=missing value in the form",
},
}

Expand Down
Loading