Reputation: 150
I need to retrieve the values of sub-claims from a JWT in Go.
I have (legacy) JWTs I need to parse in go, which contain a custom claim "data" which holds an Json-Object consisting of some fields (userid, username), so
{ [...standard claims]..., "data":{"id":"123", "name":"JohnDoe"} }
With using github.com/dgrijalva/jwt-go
, I can parse the token and access the claims with this:
keyfunc := func(token *jwt.Token) (interface{}, error) {
return tknkey, nil
}
tkn, err := jwt.Parse(tknStr, keyfunc)
cl, _ := tkn.Claims.(jwt.MapClaims)
This works fine for the standard claims, and I also get the field names from the Json-Sub-Object in the "data" claim, but not the field values (all empty strings). I also tried setting up structs matching the claim hierarchy (outer and inner struct), with no success.
What would be the way to access the values of the sub-claims?
Upvotes: 6
Views: 15848
Reputation: 51
Try this
type UserData struct {
Id string `json:"id"`
Name string `json:"name"`
}
type JWTClaim struct {
Data UserData `json:"data"`
jwt.StandardClaims
}
token, err := jwt.ParseWithClaims(
signedToken,
&JWTClaim{},
func(token *jwt.Token) (interface{}, error) {
return []byte(jwtKey), nil
},
)
Upvotes: 3
Reputation: 16324
You can use jwt.MapClaims
with "data": map[string]string
with the following steps.
In the below example, jwt
is github.com/golang-jwt/jwt/v4
. Running code for this example is at github.com/grokify/goauth/examples/jwt/main.go.
Create the custom MapClaims
with a data
map. Add a custom data.name
property which we'll extract below.
claims := &jwt.MapClaims{
"iss": "issuer",
"exp": time.Now().Add(time.Hour).Unix(),
"data": map[string]string{
"id": "123",
"name": "JohnDoe",
},
}
For this example, we'll use a symmetric key.
token := jwt.NewWithClaims(
jwt.SigningMethodHS256,
claims)
secretKey := "foobar"
tokenString, err := token.SignedString([]byte(secretKey))
MapClaims
.Use the secretKey
again since this example uses HS256.
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
return []byte(secretKey), nil
})
claims := token.Claims.(jwt.MapClaims)
Cast data
to map[string]interface{}
and cast data["name"]
to string
.
data := claims["data"].(map[string]interface{})
name := data["name"].(string)
Upvotes: 11