Description
Issue Description
Unable to unmarshal JWT due to jwt-go library version not supporting array audiences (aud
).
This issue is due to library github.com/dgrijalva/jwt-go
. Echo is currently on version v3.2.0+incompatible
. This is fixed in version v4.0.0-preview1
, specifically commit ec0a89a.
Upgrading from github.com/dgrijalva/jwt-go v3.2.0+incompatible
to github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1
should fix this error.
Occurs when using Keycloak 10.0.2 as OAuth provider.
Checklist
- Dependencies installed
- No typos
- Searched existing issues and docs
Expected behaviour
JWT middleware is able to unmarshal JWT when the OAuth token contains an audience field which is an array, as allowed by RFC 7519.
Actual behaviour
JWT middleware expects the aud
field of the JWT to be a string only, and so throws an error when it is an array.
Steps to reproduce
- Connect to OAuth using user where audience is not single value, using e.g. Keycloak v10.0.2.
- Make request to Echo API using OAuth token where API uses JWT middleware.
- Observe error:
{"time":"2020-07-21T17:30:12.391848+01:00","id":"","remote_ip":"127.0.0.1","host":"localhost:8000","method":"GET","uri":"/hello","user_agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:79.0) Gecko/20100101 Firefox/79.0","status":401,"error":"code=401, message=invalid or expired jwt, internal=json: cannot unmarshal array into Go struct field JwtClaims.aud of type string","latency":254265,"latency_human":"254.265µs","bytes_in":0,"bytes_out":37}
Working code to debug
package main
import (
echoMiddleware "github.com/labstack/echo/middleware"
"github.com/labstack/echo/v4"
"github.com/dgrijalva/jwt-go"
)
// Retrieved via call to Keycloak RESTful API in this case. Code for retrieving and processing the
// certificates is a bit too length to include here.
var RSAPublicKeys map[string]interface{}
type JwtUser struct {
*jwt.StandardClaims
*jwt.Token
}
type JwtClaims struct {
jwt.StandardClaims
}
func main() {
e := echo.New()
apiGroup := e.Group("/")
apiGroup.Use(echoMiddleware.JWTWithConfig(echoMiddleware.JWTConfig{
SigningKeys: RSAPublicKeys,
SigningMethod: jwt.SigningMethodRS256.Name,
Claims: &jwt.StandardClaims{},
}))
apiGroup.GET("hello", greeter)
e.Logger.Fatal(e.Start(":8000"))
}
func greeter(c echo.Context) error {
user := getJwtUser(c)
return c.String(
http.StatusOK,
fmt.Sprintf("Hey there %v!", user),
)
}
func getJwtUser(c echo.Context) JwtUser {
token := c.Get("user").(*jwt.Token)
claims := token.Claims.(*JwtClaims)
return JwtUser{
JwtClaims: claims,
Token: token,
}
}
Version/commit
Echo version v4.1.16
.
Edit: Fixed code example after feedback.