gojwtjwt-go

How to access JWT sub-claims using Go?


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?


Solution

  • 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.

    Step 1.1: Create the claims

    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",
        },
    }
    

    Step 1.2: Create the JWT

    For this example, we'll use a symmetric key.

    token := jwt.NewWithClaims(
        jwt.SigningMethodHS256,
        claims)
    
    secretKey := "foobar"
    
    tokenString, err := token.SignedString([]byte(secretKey))
    

    Step 2.1: Parse the token and cast claims to 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)
    

    Step 2.2: Extract custom sub-claim

    Cast data to map[string]interface{} and cast data["name"] to string.

    data := claims["data"].(map[string]interface{})
    name := data["name"].(string)