From 41055df13052da697fd2c4526f7d6117cd4b8791 Mon Sep 17 00:00:00 2001 From: Alex Guerrieri Date: Tue, 22 Jul 2025 08:08:14 +0200 Subject: [PATCH 1/4] Add JWT token option to S2SClient --- go.mod | 6 +++--- s2s.go | 20 +++++++++++++++----- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 5195ab9..36c8dc2 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,10 @@ require ( github.com/go-chi/metrics v0.1.0 github.com/go-chi/traceid v0.2.0 github.com/go-chi/transport v0.4.0 + github.com/goware/base64 v0.1.0 + github.com/jxskiss/base62 v1.1.0 github.com/lestrrat-go/jwx/v2 v2.1.3 + github.com/spf13/cobra v1.9.1 github.com/stretchr/testify v1.10.0 ) @@ -20,9 +23,7 @@ require ( github.com/decred/dcrd/dcrec/secp256k1/v4 v4.3.0 // indirect github.com/goccy/go-json v0.10.3 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/goware/base64 v0.1.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/jxskiss/base62 v1.1.0 // indirect github.com/kr/text v0.2.0 // indirect github.com/lestrrat-go/blackmagic v1.0.2 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect @@ -37,7 +38,6 @@ require ( github.com/prometheus/procfs v0.15.1 // indirect github.com/rogpeppe/go-internal v1.12.0 // indirect github.com/segmentio/asm v1.2.0 // indirect - github.com/spf13/cobra v1.9.1 // indirect github.com/spf13/pflag v1.0.6 // indirect golang.org/x/crypto v0.31.0 // indirect golang.org/x/sync v0.10.0 // indirect diff --git a/s2s.go b/s2s.go index 49deae7..a543f06 100644 --- a/s2s.go +++ b/s2s.go @@ -14,9 +14,15 @@ import ( ) type S2SClientConfig struct { - Service string - JWTSecret string - AccessKey string + // JWTToken is the JWT token to use for authentication. + JWTToken string + // JWTSecret is the secret key used to create the JWT token. + JWTSecret string + // Service is used in the service claim of the JWT token. + Service string + // AccessKey is an optional access key to use for authentication. + AccessKey string + // DebugRequests enables logging of HTTP requests. DebugRequests bool } @@ -28,9 +34,13 @@ func S2SClient(cfg *S2SClientConfig) *http.Client { Transport: transport.Chain(http.DefaultTransport, traceid.Transport, transport.SetHeader("User-Agent", fmt.Sprintf("sequence/%s", serviceName)), - transport.If(cfg.JWTSecret != "", + transport.If(cfg.JWTSecret != "" || cfg.JWTToken != "", transport.SetHeaderFunc("Authorization", func(req *http.Request) string { - return "BEARER " + S2SToken(cfg.JWTSecret, map[string]any{"service": serviceName}) + token := cfg.JWTToken + if token == "" { + token = S2SToken(cfg.JWTSecret, map[string]any{"service": serviceName}) + } + return "BEARER " + token }), ), transport.If(cfg.AccessKey != "", From 0707d96aa453376c2694dc052910bb1abc5a910e Mon Sep 17 00:00:00 2001 From: Alex Guerrieri Date: Tue, 22 Jul 2025 08:15:15 +0200 Subject: [PATCH 2/4] Add clarification to S2SClient function documentation regarding JWT token creation --- s2s.go | 1 + 1 file changed, 1 insertion(+) diff --git a/s2s.go b/s2s.go index a543f06..1dfb573 100644 --- a/s2s.go +++ b/s2s.go @@ -27,6 +27,7 @@ type S2SClientConfig struct { } // Service-to-service HTTP client for internal communication between Sequence services. +// If JWTSecret is provided, it will create a HS256 JWT token with the service name in the claims. func S2SClient(cfg *S2SClientConfig) *http.Client { serviceName := cmp.Or(cfg.Service, filepath.Base(os.Args[0])) From 93e4c80b4da9dc88f47dc5b0238c56054733cba8 Mon Sep 17 00:00:00 2001 From: Alex Guerrieri Date: Tue, 22 Jul 2025 08:16:34 +0200 Subject: [PATCH 3/4] Add clarification to S2SClient function documentation regarding JWTToken precedence --- s2s.go | 1 + 1 file changed, 1 insertion(+) diff --git a/s2s.go b/s2s.go index 1dfb573..abc7b25 100644 --- a/s2s.go +++ b/s2s.go @@ -28,6 +28,7 @@ type S2SClientConfig struct { // Service-to-service HTTP client for internal communication between Sequence services. // If JWTSecret is provided, it will create a HS256 JWT token with the service name in the claims. +// If both JWTSecret and JWTToken are provided, JWTToken will take precedence. func S2SClient(cfg *S2SClientConfig) *http.Client { serviceName := cmp.Or(cfg.Service, filepath.Base(os.Args[0])) From 948295dc73bd7aa040dd9ee2de4b74715a996d98 Mon Sep 17 00:00:00 2001 From: Vojtech Vitek Date: Tue, 22 Jul 2025 17:42:24 +0200 Subject: [PATCH 4/4] Use transport.SetHeader() for the static JWT token --- s2s.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/s2s.go b/s2s.go index abc7b25..eaa024b 100644 --- a/s2s.go +++ b/s2s.go @@ -14,13 +14,13 @@ import ( ) type S2SClientConfig struct { - // JWTToken is the JWT token to use for authentication. + // JWTToken is the static JWT token used for authentication. JWTToken string - // JWTSecret is the secret key used to create the JWT token. + // JWTSecret is the secret key used to dynamically create JWT BEARER token for authorization. JWTSecret string // Service is used in the service claim of the JWT token. Service string - // AccessKey is an optional access key to use for authentication. + // AccessKey is an optional access key used for authentication. AccessKey string // DebugRequests enables logging of HTTP requests. DebugRequests bool @@ -36,15 +36,14 @@ func S2SClient(cfg *S2SClientConfig) *http.Client { Transport: transport.Chain(http.DefaultTransport, traceid.Transport, transport.SetHeader("User-Agent", fmt.Sprintf("sequence/%s", serviceName)), - transport.If(cfg.JWTSecret != "" || cfg.JWTToken != "", + transport.If(cfg.JWTSecret != "", transport.SetHeaderFunc("Authorization", func(req *http.Request) string { - token := cfg.JWTToken - if token == "" { - token = S2SToken(cfg.JWTSecret, map[string]any{"service": serviceName}) - } - return "BEARER " + token + return "BEARER " + S2SToken(cfg.JWTSecret, map[string]any{"service": serviceName}) }), ), + transport.If(cfg.JWTToken != "", + transport.SetHeader("Authorization", "BEARER "+cfg.JWTToken), + ), transport.If(cfg.AccessKey != "", transport.SetHeader("X-Access-Key", cfg.AccessKey), ),