package jose import ( "encoding/json" "fmt" "math" "time" ) type Claims map[string]interface{} func (c Claims) Add(name string, value interface{}) { c[name] = value } func (c Claims) StringClaim(name string) (string, bool, error) { cl, ok := c[name] if !ok { return "", false, nil } v, ok := cl.(string) if !ok { return "", false, fmt.Errorf("unable to parse claim as string: %v", name) } return v, true, nil } func (c Claims) StringsClaim(name string) ([]string, bool, error) { cl, ok := c[name] if !ok { return nil, false, nil } if v, ok := cl.([]string); ok { return v, true, nil } // When unmarshaled, []string will become []interface{}. if v, ok := cl.([]interface{}); ok { var ret []string for _, vv := range v { str, ok := vv.(string) if !ok { return nil, false, fmt.Errorf("unable to parse claim as string array: %v", name) } ret = append(ret, str) } return ret, true, nil } return nil, false, fmt.Errorf("unable to parse claim as string array: %v", name) } func (c Claims) Int64Claim(name string) (int64, bool, error) { cl, ok := c[name] if !ok { return 0, false, nil } v, ok := cl.(int64) if !ok { vf, ok := cl.(float64) if !ok { return 0, false, fmt.Errorf("unable to parse claim as int64: %v", name) } v = int64(vf) } return v, true, nil } func (c Claims) Float64Claim(name string) (float64, bool, error) { cl, ok := c[name] if !ok { return 0, false, nil } v, ok := cl.(float64) if !ok { vi, ok := cl.(int64) if !ok { return 0, false, fmt.Errorf("unable to parse claim as float64: %v", name) } v = float64(vi) } return v, true, nil } func (c Claims) TimeClaim(name string) (time.Time, bool, error) { v, ok, err := c.Float64Claim(name) if !ok || err != nil { return time.Time{}, ok, err } s := math.Trunc(v) ns := (v - s) * math.Pow(10, 9) return time.Unix(int64(s), int64(ns)).UTC(), true, nil } func decodeClaims(payload []byte) (Claims, error) { var c Claims if err := json.Unmarshal(payload, &c); err != nil { return nil, fmt.Errorf("malformed JWT claims, unable to decode: %v", err) } return c, nil } func marshalClaims(c Claims) ([]byte, error) { b, err := json.Marshal(c) if err != nil { return nil, err } return b, nil } func encodeClaims(c Claims) (string, error) { b, err := marshalClaims(c) if err != nil { return "", err } return encodeSegment(b), nil }