Skip to content

Commit 9052334

Browse files
committed
Echo v5 support
1 parent f4f9aa9 commit 9052334

12 files changed

Lines changed: 162 additions & 981 deletions

.github/workflows/echo.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ jobs:
2020
test:
2121
strategy:
2222
matrix:
23-
os: [ubuntu-latest, macos-latest, windows-latest]
23+
os: [ ubuntu-latest, macos-latest, windows-latest ]
2424
# Each major Go release is supported until there are two newer major releases. https://golang.org/doc/devel/release.html#policy
2525
# Echo tests with last four major releases (unless there are pressing vulnerabilities)
2626
# As we depend on `golang.org/x/` libraries which only support last 2 Go releases we could have situations when
2727
# we derive from last four major releases promise.
28-
go: ["1.24", "1.25"]
28+
go: [ "1.24", "1.25" ]
2929
name: ${{ matrix.os }} @ Go ${{ matrix.go }}
3030
runs-on: ${{ matrix.os }}
3131
steps:

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Changelog
22

3+
## v5.0.0 - TBA
4+
5+
* Echo v5 support
6+
7+
38
## v4.4.0 - 2025-11-20
49

510
**Enhancements**

README.md

Lines changed: 55 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,39 @@ as JWT implementation.
1414
This repository does not use semantic versioning. MAJOR version tracks which Echo version should be used. MINOR version
1515
tracks API changes (possibly backwards incompatible) and PATCH version is incremented for fixes.
1616

17-
NB: When `golang-jwt` MAJOR version changes this library will release MINOR version with **breaking change**. Always
17+
NB: When `golang-jwt` MAJOR version changes this library will release MINOR version with **breaking change**. Always
1818
add at least one integration test in your project.
1919

20-
For Echo `v4` use `v4.x.y` releases.
20+
For Echo `v5` use `v5.x.y` releases.
2121
Minimal needed Echo versions:
22+
23+
* `v5.0.0` needs Echo `v5.0.0+`
2224
* `v4.0.0` needs Echo `v4.7.0+`
2325

2426
`main` branch is compatible with the latest Echo version.
2527

2628
## Usage
2729

2830
Add JWT middleware dependency with go modules
31+
2932
```bash
30-
go get github.com/labstack/echo-jwt/v4
33+
go get github.com/labstack/echo-jwt/v5
3134
```
3235

3336
Use as import statement
37+
3438
```go
35-
import "github.com/labstack/echo-jwt/v4"
39+
import "github.com/labstack/echo-jwt/v5"
3640
```
3741

3842
Add middleware in simplified form, by providing only the secret key
43+
3944
```go
4045
e.Use(echojwt.JWT([]byte("secret")))
4146
```
4247

4348
Add middleware with configuration options
49+
4450
```go
4551
e.Use(echojwt.WithConfig(echojwt.Config{
4652
// ...
@@ -50,15 +56,16 @@ e.Use(echojwt.WithConfig(echojwt.Config{
5056
```
5157

5258
Extract token in handler
59+
5360
```go
5461
import "github.com/golang-jwt/jwt/v5"
5562

5663
// ...
5764

58-
e.GET("/", func(c echo.Context) error {
59-
token, ok := c.Get("user").(*jwt.Token) // by default token is stored under `user` key
60-
if !ok {
61-
return errors.New("JWT token missing or invalid")
65+
e.GET("/", func(c *echo.Context) error {
66+
token, err := echo.ContextGet[*jwt.Token](c,"user")
67+
if err != nil {
68+
return echo.ErrUnauthorized.Wrap(err)
6269
}
6370
claims, ok := token.Claims.(jwt.MapClaims) // by default claims is of type `jwt.MapClaims`
6471
if !ok {
@@ -70,8 +77,12 @@ e.GET("/", func(c echo.Context) error {
7077

7178
## IMPORTANT: Integration Testing with JWT Library
7279

73-
Ensure that your project includes at least one integration test to detect changes in major versions of the `golang-jwt/jwt` library early.
74-
This is crucial because type assertions like `token := c.Get("user").(*jwt.Token)` may fail silently if the imported version of the JWT library (e.g., `import "github.com/golang-jwt/jwt/v5"`) differs from the version used internally by dependencies (e.g., echo-jwt may now use `v6`). Such discrepancies can lead to invalid casts, causing your handlers to panic or throw errors. Integration tests help safeguard against these version mismatches.
80+
Ensure that your project includes at least one integration test to detect changes in major versions of the
81+
`golang-jwt/jwt` library early.
82+
This is crucial because type assertions like `token := c.Get("user").(*jwt.Token)` may fail silently if the imported
83+
version of the JWT library (e.g., `import "github.com/golang-jwt/jwt/v5"`) differs from the version used internally by
84+
dependencies (e.g., echo-jwt may now use `v6`). Such discrepancies can lead to invalid casts, causing your handlers to
85+
panic or throw errors. Integration tests help safeguard against these version mismatches.
7586

7687
```go
7788
func TestIntegrationMiddlewareWithHandler(t *testing.T) {
@@ -97,55 +108,58 @@ func TestIntegrationMiddlewareWithHandler(t *testing.T) {
97108
}
98109
```
99110

100-
101111
## Full example
102112

103113
```go
104114
package main
105115

106116
import (
107-
"errors"
108-
"github.com/golang-jwt/jwt/v5"
109-
"github.com/labstack/echo-jwt/v4"
110-
"github.com/labstack/echo/v4"
111-
"github.com/labstack/echo/v4/middleware"
112-
"log"
113-
"net/http"
114-
)
117+
"errors"
118+
"log/slog"
115119

116-
func main() {
117-
e := echo.New()
118-
e.Use(middleware.Logger())
119-
e.Use(middleware.Recover())
120+
"github.com/golang-jwt/jwt/v5"
121+
"github.com/labstack/echo-jwt/v5"
122+
"github.com/labstack/echo/v5"
123+
"github.com/labstack/echo/v5/middleware"
120124

121-
e.Use(echojwt.WithConfig(echojwt.Config{
122-
SigningKey: []byte("secret"),
123-
}))
125+
"net/http"
126+
)
124127

125-
e.GET("/", func(c echo.Context) error {
126-
token, ok := c.Get("user").(*jwt.Token) // by default token is stored under `user` key
127-
if !ok {
128-
return errors.New("JWT token missing or invalid")
129-
}
130-
claims, ok := token.Claims.(jwt.MapClaims) // by default claims is of type `jwt.MapClaims`
131-
if !ok {
132-
return errors.New("failed to cast claims as jwt.MapClaims")
133-
}
134-
return c.JSON(http.StatusOK, claims)
135-
})
136-
137-
if err := e.Start(":8080"); err != http.ErrServerClosed {
138-
log.Fatal(err)
139-
}
128+
func main() {
129+
e := echo.New()
130+
e.Use(middleware.RequestLogger())
131+
e.Use(middleware.Recover())
132+
133+
e.Use(echojwt.WithConfig(echojwt.Config{
134+
SigningKey: []byte("secret"),
135+
}))
136+
137+
e.GET("/", func(c *echo.Context) error {
138+
token, err := echo.ContextGet[*jwt.Token](c, "user")
139+
if err != nil {
140+
return echo.ErrUnauthorized.Wrap(err)
141+
}
142+
claims, ok := token.Claims.(jwt.MapClaims) // by default claims is of type `jwt.MapClaims`
143+
if !ok {
144+
return errors.New("failed to cast claims as jwt.MapClaims")
145+
}
146+
return c.JSON(http.StatusOK, claims)
147+
})
148+
149+
if err := e.Start(":8080"); err != nil {
150+
slog.Error("Failed to start server", "error", err)
151+
}
140152
}
141153
```
142154

143155
Test with
156+
144157
```bash
145158
curl -v -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ" http://localhost:8080
146159
```
147160

148161
Output should be
162+
149163
```bash
150164
* Trying 127.0.0.1:8080...
151165
* Connected to localhost (127.0.0.1) port 8080 (#0)

0 commit comments

Comments
 (0)