Description
Description
I believe this is an isssue with the underlying jwt-go
code, but I've been spending a lot of time struggling to make progress with this. I've updated my go modules and I'm currently on v1 of the jwt-middleware
and v3.2.2 of the form3tech-oss/jwt-go
packages
When presented with an audience which is an array, the library cannot unmarshal into the CustomClaims object and gives:
json: cannot unmarshal string into Go struct field CustomClaims.aud of type []string
Provide a clear and concise description of the issue, including what you expected to happen.
I believe the core issue lies in ParseWithClaims
, but I can't say for sure
Reproduction
I'm mostly going off of the Auth0 Go Quickstart, and my code looks like this:
Middleware:
func (api API) SetupJWTMiddleware() *jwtmiddleware.JWTMiddleware {
authJWTMiddleware := jwtmiddleware.New(jwtmiddleware.Options{
ValidationKeyGetter: func(token *jwt.Token) (interface{}, error) {
checkAudience := token.Claims.(jwt.MapClaims).VerifyAudience(api.AuthConfig.Audience, false)
if !checkAudience {
return token, errors.New("could not verify token audience")
}
checkIssuer := token.Claims.(jwt.MapClaims).VerifyIssuer(api.AuthConfig.Issuer, false)
if !checkIssuer {
return token, errors.New("could not verify token issuer")
}
cert, err := api.getPemCert(token)
if err != nil {
panic(err)
}
result, _ := jwt.ParseRSAPublicKeyFromPEM([]byte(cert))
return result, nil
},
SigningMethod: jwt.SigningMethodRS256,
})
return authJWTMiddleware
}
Authenticated request handler:
func (api API) AuthedEndpoint(apiEndpoint http.HandlerFunc) http.HandlerFunc {
return func(response http.ResponseWriter, request *http.Request) {
err := api.AuthMiddleware.CheckJWT(response, request)
if err != nil {
return // CheckJWT writes to response for us
}
token, err := jwtmiddleware.FromAuthHeader(request)
if err != nil {
http.Error(response, err.Error(), http.StatusForbidden)
return
}
hasScope := api.checkScope("some-scope", token)
if !hasScope {
http.Error(response, "insufficient scope to access endpoint", http.StatusForbidden)
return
}
apiEndpoint(response, request)
}
}
checkScope:
func (api API) checkScope(scope string, tokenString string) bool {
token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
cert, err := api.getPemCert(token)
if err != nil {
return nil, err
}
result, _ := jwt.ParseRSAPublicKeyFromPEM([]byte(cert))
return result, nil
})
if err != nil {
fmt.Printf(err.Error())
}
claims, ok := token.Claims.(*CustomClaims)
hasScope := false
if ok && token.Valid {
scopes := strings.Split(claims.Scope, " ")
for index := range scopes {
if scopes[index] == scope {
hasScope = true
}
}
}
return hasScope
}
I ran into this issue when trying to hit authenticated endpoints with a token generated with the React useAuth0
hook, specifically getAccessTokenSilently
, which gives me a token with:
"aud": [
"my.project.domain/api/",
"https://project.us.auth0.com/userinfo"
],