golang-jwt / jwt

Go implementation of JSON Web Tokens (JWT).

Home Page:https://golang-jwt.github.io/jwt/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Avoid use of `json.NewDecoder` if not needed

oxisto opened this issue · comments

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