We use both json.Unmarshal(for the header) and json.NewDecoder/Decode in ParseUnverified (for the claims). However, we only really need to use the decode type if we have UseNumber enabled. The decoder has about a 30 % performance drawback compared to only using json.Unmarshal + more allocations.
var (
token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJmb28iOiJiYXIifQ.FhkiHkoESI_cG3NPigFrxEk9Z60_oXrOT2vGm9Pn6RDgYNovYORQmmA0zs1AoAOf09ly2Nx2YAg6ABqAYga1AcMFkJljwxTT5fYphTuqpWdy4BELeSYJx5Ty2gmr8e7RonuUztrdD5WfPqLKMm1Ozp_T6zALpRmwTIW0QPnaBXaQD90FplAg46Iy1UlDKr-Eupy0i5SLch5Q-p2ZpaL_5fnTIUDlxC3pWhJTyx_71qDI-mAA_5lE_VdroOeflG56sSmDxopPEG3bFlSu1eowyBfxtu0_CuVd-M42RU75Zc4Gsj6uV77MBtbMrf4_7M_NUTSgoIF3fRqxrj0NzihIBg"
)
func BenchmarkBearer(b *testing.B) {
b.Run("json.Unmarshal only", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
var header = map[string]any{}
var claims = map[string]any{}
var parts = strings.Split(token, ".")
headerBytes, _ := base64.URLEncoding.DecodeString(parts[0])
claimBytes, _ := base64.URLEncoding.DecodeString(parts[1])
json.Unmarshal(headerBytes, &header)
json.Unmarshal(claimBytes, &claims)
}
})
b.Run("json.Unmarshal + json.NewDecoder.Decode", func(b *testing.B) {
b.ResetTimer()
for i := 0; i < b.N; i++ {
var header = map[string]any{}
var claims = map[string]any{}
var parts = strings.Split(token, ".")
headerBytes, _ := base64.URLEncoding.DecodeString(parts[0])
claimBytes, _ := base64.URLEncoding.DecodeString(parts[1])
json.Unmarshal(headerBytes, &header)
dec := json.NewDecoder(bytes.NewReader(claimBytes))
dec.Decode(&claims)
}
})
}
We use both
json.Unmarshal
(for the header) andjson.NewDecoder
/Decode
inParseUnverified
(for the claims). However, we only really need to use the decode type if we haveUseNumber
enabled. The decoder has about a 30 % performance drawback compared to only usingjson.Unmarshal
+ more allocations.Results: