kataras / jwt

A fast and simple JWT implementation for Go
MIT License
204 stars 19 forks source link

Generating the wrong token when customising claims #16

Open hbread00 opened 1 year ago

hbread00 commented 1 year ago

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