Skip to content

Commit

Permalink
Set json encoding precision (golang-jwt#162)
Browse files Browse the repository at this point in the history
  • Loading branch information
mfridman authored and oxisto committed Feb 21, 2023
1 parent 1707cb2 commit 57abf5e
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 6 deletions.
6 changes: 5 additions & 1 deletion types.go
Expand Up @@ -49,9 +49,13 @@ func newNumericDateFromSeconds(f float64) *NumericDate {
// MarshalJSON is an implementation of the json.RawMessage interface and serializes the UNIX epoch
// represented in NumericDate to a byte array, using the precision specified in TimePrecision.
func (date NumericDate) MarshalJSON() (b []byte, err error) {
var prec int
if TimePrecision < time.Second {
prec = int(math.Log10(float64(time.Second) / float64(TimePrecision)))
}
f := float64(date.Truncate(TimePrecision).UnixNano()) / float64(time.Second)

return []byte(strconv.FormatFloat(f, 'f', -1, 64)), nil
return []byte(strconv.FormatFloat(f, 'f', prec, 64)), nil
}

// UnmarshalJSON is an implementation of the json.RawMessage interface and deserializses a
Expand Down
54 changes: 49 additions & 5 deletions types_test.go
Expand Up @@ -18,12 +18,10 @@ func TestNumericDate(t *testing.T) {

jwt.TimePrecision = time.Microsecond

raw := `{"iat":1516239022,"exp":1516239022.12345}`
raw := `{"iat":1516239022.000000,"exp":1516239022.123450}`

err := json.Unmarshal([]byte(raw), &s)

if err != nil {
t.Errorf("Unexpected error: %s", err)
if err := json.Unmarshal([]byte(raw), &s); err != nil {
t.Fatalf("Unexpected error: %s", err)
}

b, _ := json.Marshal(s)
Expand Down Expand Up @@ -65,3 +63,49 @@ func TestSingleArrayMarshal(t *testing.T) {
t.Errorf("Serialized format of string array mismatch. Expecting: %s Got: %s", string(expected), string(b))
}
}

func TestNumericDate_MarshalJSON(t *testing.T) {
// Do not run this test in parallel because it's changing
// global state.
oldPrecision := jwt.TimePrecision
t.Cleanup(func() {
jwt.TimePrecision = oldPrecision
})

tt := []struct {
in time.Time
want string
precision time.Duration
}{
{time.Unix(5243700879, 0), "5243700879", time.Second},
{time.Unix(5243700879, 0), "5243700879.000", time.Millisecond},
{time.Unix(5243700879, 0), "5243700879.000001", time.Microsecond},
{time.Unix(5243700879, 0), "5243700879.000000954", time.Nanosecond},
//
{time.Unix(4239425898, 0), "4239425898", time.Second},
{time.Unix(4239425898, 0), "4239425898.000", time.Millisecond},
{time.Unix(4239425898, 0), "4239425898.000000", time.Microsecond},
{time.Unix(4239425898, 0), "4239425898.000000000", time.Nanosecond},
//
{time.Unix(0, 1644285000210402000), "1644285000", time.Second},
{time.Unix(0, 1644285000210402000), "1644285000.210", time.Millisecond},
{time.Unix(0, 1644285000210402000), "1644285000.210402", time.Microsecond},
{time.Unix(0, 1644285000210402000), "1644285000.210402012", time.Nanosecond},
//
{time.Unix(0, 1644285315063096000), "1644285315", time.Second},
{time.Unix(0, 1644285315063096000), "1644285315.063", time.Millisecond},
{time.Unix(0, 1644285315063096000), "1644285315.063096", time.Microsecond},
{time.Unix(0, 1644285315063096000), "1644285315.063096046", time.Nanosecond},
}

for i, tc := range tt {
jwt.TimePrecision = tc.precision
by, err := jwt.NewNumericDate(tc.in).MarshalJSON()
if err != nil {
t.Fatal(err)
}
if got := string(by); got != tc.want {
t.Errorf("[%d]: failed encoding: got %q want %q", i, got, tc.want)
}
}
}

0 comments on commit 57abf5e

Please sign in to comment.