Skip to content

Avoid use of json.NewDecoder if not needed #303

Closed
@oxisto

Description

@oxisto

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)
		}
	})
}

Results:

Running tool: /opt/homebrew/bin/go test -benchmem -run=^$ -bench ^BenchmarkBearer$ github.com/golang-jwt/jwt/v5

2023/04/02 23:00:58 Listening...
goos: darwin
goarch: arm64
pkg: github.com/golang-jwt/jwt/v5
BenchmarkBearer/json.Unmarshal_only-8         	 1000000	      1076 ns/op	    1016 B/op	      25 allocs/op
BenchmarkBearer/json.Unmarshal_+_json.NewDecoder.Decode-8         	  830516	      1436 ns/op	    3264 B/op	      27 allocs/op
PASS
ok  	github.com/golang-jwt/jwt/v5	2.405s

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions