jwt icon indicating copy to clipboard operation
jwt copied to clipboard

Generating the wrong token when customising claims

Open hbread00 opened this issue 1 year ago • 0 comments

Situation

type fooClaims struct {
	Foo string `json:"foo"`
}
func main() {
	key := ([]byte("foo"))
	foo := fooClaims{
		Foo: "foo",
	}
	token, err :=  jwt.Sign(jwt.HS256, key, foo, jwt.MaxAge(time.Second*1))
	if err != nil {
		panic(err)
	}
	fmt.Println(token)
}

This will successfully output a token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJmb28iLH0.x3KzbXc5PoGcb42h2vETFtGn5l1K3rhdJlQmgYGBR-k Parsing the payload, the message looks like this {"foo":"foo",} This is not a valid json because it ends with "," This causes the verify to return an error because the Json could not be parsed jwt: payload is not a type of JSON This only happens if MaxAge is not greater than 1 second

Reasons for speculation

I didn't do detailed testing, just inferred from the code

claims.go

MaxAge did not add the relevant information to the claims as the input time did not exceed 1 second

func MaxAge(maxAge time.Duration) SignOptionFunc {
	return func(c *Claims) {
		if maxAge <= time.Second {
			return
		}
		now := Clock()
		c.Expiry = now.Add(maxAge).Unix()
		c.IssuedAt = now.Unix()
	}
}

Custom claims are added with "," at the end

func Merge(claims interface{}, other interface{}) []byte {
	claimsB, err := Marshal(claims)
	if err != nil {
		return nil
	}

	otherB, err := Marshal(other)
	if err != nil {
		return nil
	}

	if len(otherB) == 0 {
		return claimsB
	}

	claimsB = claimsB[0 : len(claimsB)-1] // remove last '}'
	otherB = otherB[1:]                   // remove first '{'

	raw := append(claimsB, ',')
	raw = append(raw, otherB...)
	return raw
}

This resulted in the wrong payload being generated

hbread00 avatar Apr 18 '23 09:04 hbread00