diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index da6dcbf..1737483 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -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 diff --git a/.github/workflows/echo.yml b/.github/workflows/echo.yml index 73b3db5..a958cba 100644 --- a/.github/workflows/echo.yml +++ b/.github/workflows/echo.yml @@ -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: @@ -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 }} @@ -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 @@ -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 }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 9000945..54efdb8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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** diff --git a/go.mod b/go.mod index 12f014c..b2c46c7 100644 --- a/go.mod +++ b/go.mod @@ -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 ( @@ -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 ) diff --git a/go.sum b/go.sum index 85a95dc..ba0b2a5 100644 --- a/go.sum +++ b/go.sum @@ -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= @@ -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= diff --git a/jwt.go b/jwt.go index 1e97d30..10e5f2d 100644 --- a/jwt.go +++ b/jwt.go @@ -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 { @@ -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 { @@ -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 } diff --git a/jwt_test.go b/jwt_test.go index ecd26ad..1b47494 100644 --- a/jwt_test.go +++ b/jwt_test.go @@ -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", @@ -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", @@ -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{ @@ -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", @@ -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", }, }