diff --git a/go.mod b/go.mod index 8b22d8bbf..023497c56 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.26 require ( filippo.io/csrf v0.2.1 - gopkg.in/square/go-jose.v2 v2.6.0 + github.com/go-jose/go-jose/v4 v4.1.4 tailscale.com v1.94.2 ) diff --git a/go.sum b/go.sum index 348c4b380..78751a6c3 100644 --- a/go.sum +++ b/go.sum @@ -56,8 +56,6 @@ github.com/creachadair/taskgroup v0.13.2 h1:3KyqakBuFsm3KkXi/9XIb0QcA8tEzLHLgaoi github.com/creachadair/taskgroup v0.13.2/go.mod h1:i3V1Zx7H8RjwljUEeUWYT30Lmb9poewSb2XI1yTwD0g= github.com/creack/pty v1.1.23 h1:4M6+isWdcStXEf15G/RbrMPOQj1dZ7HPZCGwE4kOeP0= github.com/creack/pty v1.1.23/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa h1:h8TfIT1xc8FWbwwpmHn1J5i43Y0uZP97GqasGCzSRJk= github.com/dblohm7/wingoes v0.0.0-20240119213807-a09d6be7affa/go.mod h1:Nx87SkVqTKd8UtT+xu7sM/l+LgXs6c0aHrlKusR+2EQ= github.com/dgryski/go-metro v0.0.0-20180109044635-280f6062b5bc h1:8WFBn63wegobsYAX0YjD+8suexZDga5CctH4CCTx2+8= @@ -74,6 +72,8 @@ github.com/gaissmai/bart v0.18.0 h1:jQLBT/RduJu0pv/tLwXE+xKPgtWJejbxuXAR+wLJafo= github.com/gaissmai/bart v0.18.0/go.mod h1:JJzMAhNF5Rjo4SF4jWBrANuJfqY+FvsFhW7t1UZJ+XY= github.com/github/fakeca v0.1.0 h1:Km/MVOFvclqxPM9dZBC4+QE564nU4gz4iZ0D9pMw28I= github.com/github/fakeca v0.1.0/go.mod h1:+bormgoGMMuamOscx7N91aOuUST7wdaJ2rNjeohylyo= +github.com/go-jose/go-jose/v4 v4.1.4 h1:moDMcTHmvE6Groj34emNPLs/qtYXRVcd6S7NHbHz3kA= +github.com/go-jose/go-jose/v4 v4.1.4/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced h1:Q311OHjMh/u5E2TITc++WlTP5We0xNseRMkHDyvhW7I= github.com/go-json-experiment/json v0.0.0-20250813024750-ebf49471dced/go.mod h1:TiCD2a1pcmjd7YnhGH0f/zKNcCD06B029pHhzV23c2M= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= @@ -140,8 +140,6 @@ github.com/pires/go-proxyproto v0.8.1 h1:9KEixbdJfhrbtjpz/ZwCdWDD2Xem0NZ38qMYaAS github.com/pires/go-proxyproto v0.8.1/go.mod h1:ZKAAyp3cgy5Y5Mo4n9AlScrkCZwUy0g3Jf+slqQVcuU= github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/prometheus-community/pro-bing v0.4.0 h1:YMbv+i08gQz97OZZBwLyvmmQEEzyfyrrjEaAchdy3R4= github.com/prometheus-community/pro-bing v0.4.0/go.mod h1:b7wRYZtCcPmt4Sz319BykUU241rWLe1VFXyiyWK/dH4= github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk= @@ -152,8 +150,6 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/safchain/ethtool v0.3.0 h1:gimQJpsI6sc1yIqP/y8GYgiXn/NjgvpM0RNoWLVVmP0= github.com/safchain/ethtool v0.3.0/go.mod h1:SA9BwrgyAqNo7M+uaL6IYbxpm5wk3L7Mm6ocLW+CJUs= -github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= -github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e h1:PtWT87weP5LWHEY//SWsYkSO3RWRZo4OSWagh3YD2vQ= github.com/tailscale/certstore v0.1.1-0.20231202035212-d3fa0460f47e/go.mod h1:XrBNfAFN+pwoWuksbFS9Ccxnopa15zJGgXRFN90l3K4= github.com/tailscale/go-winio v0.0.0-20231025203758-c4f33415bf55 h1:Gzfnfk2TWrk8Jj4P4c1a3CtQyMaTVCznlkLZI++hok4= @@ -223,10 +219,6 @@ golang.zx2c4.com/wireguard/windows v0.5.3 h1:On6j2Rpn3OEMXqBq00QEDC7bWSZrPIHKIus golang.zx2c4.com/wireguard/windows v0.5.3/go.mod h1:9TEe8TJmtwyQebdFwAkEWOPr3prrtqm+REGFifP60hI= google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE= google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco= -gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633 h1:2gap+Kh/3F47cO6hAu3idFvsJ0ue6TRcEi2IUkv/F8k= gvisor.dev/gvisor v0.0.0-20250205023644-9414b50a5633/go.mod h1:5DMfjtclAbTIjbXqO1qCe2K5GKKxWz2JHvCChuTcJEM= honnef.co/go/tools v0.7.0-0.dev.0.20251022135355-8273271481d0 h1:5SXjd4ET5dYijLaf0O3aOenC0Z4ZafIWSpjUzsQaNho= diff --git a/server/extraclaims_test.go b/server/extraclaims_test.go index c07c5a6b1..52440c646 100644 --- a/server/extraclaims_test.go +++ b/server/extraclaims_test.go @@ -11,7 +11,7 @@ import ( "reflect" "testing" - "gopkg.in/square/go-jose.v2/jwt" + "github.com/go-jose/go-jose/v4/jwt" "tailscale.com/types/key" "tailscale.com/types/views" ) diff --git a/server/helpers_test.go b/server/helpers_test.go index e8b0fe549..87e0d0eed 100644 --- a/server/helpers_test.go +++ b/server/helpers_test.go @@ -14,7 +14,7 @@ import ( "sort" "testing" - "gopkg.in/square/go-jose.v2" + "github.com/go-jose/go-jose/v4" "tailscale.com/client/local" "tailscale.com/client/tailscale/apitype" "tailscale.com/tailcfg" diff --git a/server/oauth-metadata.go b/server/oauth-metadata.go index 48ced4d4e..37df63339 100644 --- a/server/oauth-metadata.go +++ b/server/oauth-metadata.go @@ -8,7 +8,7 @@ import ( "fmt" "net/http" - "gopkg.in/square/go-jose.v2" + "github.com/go-jose/go-jose/v4" "tailscale.com/types/views" ) diff --git a/server/server.go b/server/server.go index af76648d1..9bc812117 100644 --- a/server/server.go +++ b/server/server.go @@ -26,7 +26,7 @@ import ( "time" "filippo.io/csrf" - "gopkg.in/square/go-jose.v2" + "github.com/go-jose/go-jose/v4" "tailscale.com/client/local" "tailscale.com/client/tailscale/apitype" "tailscale.com/ipn" diff --git a/server/token.go b/server/token.go index ea1516f55..3f458bac6 100644 --- a/server/token.go +++ b/server/token.go @@ -16,7 +16,7 @@ import ( "strings" "time" - "gopkg.in/square/go-jose.v2/jwt" + "github.com/go-jose/go-jose/v4/jwt" "tailscale.com/client/tailscale/apitype" "tailscale.com/tailcfg" "tailscale.com/types/key" @@ -597,7 +597,7 @@ func (s *IDPServer) issueTokens(w http.ResponseWriter, r *http.Request, ar *Auth } // Create an OIDC token using this issuer's signer. - token, err := jwt.Signed(signer).Claims(tsClaimsWithExtra).CompactSerialize() + token, err := jwt.Signed(signer).Claims(tsClaimsWithExtra).Serialize() if err != nil { writeHTTPError(w, r, http.StatusInternalServerError, ecServerError, "error creating JWT token", err) return diff --git a/server/token_test.go b/server/token_test.go index 6e6795f8e..79ce50d46 100644 --- a/server/token_test.go +++ b/server/token_test.go @@ -14,7 +14,8 @@ import ( "testing" "time" - "gopkg.in/square/go-jose.v2/jwt" + jose "github.com/go-jose/go-jose/v4" + "github.com/go-jose/go-jose/v4/jwt" "tailscale.com/client/tailscale/apitype" "tailscale.com/tailcfg" "tailscale.com/types/key" @@ -50,7 +51,7 @@ func TestResourceIndicators(t *testing.T) { t.Fatalf("failed to unmarshal response: %v", err) } // Decode JWT to check audience - token, err := jwt.ParseSigned(resp.IDToken) + token, err := jwt.ParseSigned(resp.IDToken, []jose.SignatureAlgorithm{jose.RS256}) if err != nil { t.Fatalf("failed to parse JWT: %v", err) } @@ -87,7 +88,7 @@ func TestResourceIndicators(t *testing.T) { t.Fatalf("failed to unmarshal response: %v", err) } // Decode JWT to check audience - token, err := jwt.ParseSigned(resp.IDToken) + token, err := jwt.ParseSigned(resp.IDToken, []jose.SignatureAlgorithm{jose.RS256}) if err != nil { t.Fatalf("failed to parse JWT: %v", err) } @@ -1076,7 +1077,7 @@ func TestAZPClaimWithMultipleAudiences(t *testing.T) { } // Parse the ID token - token, err := jwt.ParseSigned(tokenResp.IDToken) + token, err := jwt.ParseSigned(tokenResp.IDToken, []jose.SignatureAlgorithm{jose.RS256}) if err != nil { t.Fatalf("failed to parse JWT: %v", err) } @@ -1092,14 +1093,20 @@ func TestAZPClaimWithMultipleAudiences(t *testing.T) { t.Fatal("aud claim not found") } - // The JWT library always serializes audience as an array - audArray, isArray := aud.([]any) - if !isArray { - t.Errorf("expected audience to be array, got %T", aud) + // go-jose/v4 serializes a single-element audience as a string + // per RFC 7519, and multi-element as an array. + var audCount int + switch v := aud.(type) { + case string: + audCount = 1 + case []any: + audCount = len(v) + default: + t.Fatalf("unexpected aud type %T", aud) } - if len(audArray) != tt.expectedAudiences { - t.Errorf("expected %d audiences, got %d", tt.expectedAudiences, len(audArray)) + if audCount != tt.expectedAudiences { + t.Errorf("expected %d audiences, got %d", tt.expectedAudiences, audCount) } // Check azp claim @@ -1337,7 +1344,7 @@ func TestServeToken(t *testing.T) { t.Fatalf("failed to unmarshal response: %v", err) } - tok, err := jwt.ParseSigned(resp.IDToken) + tok, err := jwt.ParseSigned(resp.IDToken, []jose.SignatureAlgorithm{jose.RS256}) if err != nil { t.Fatalf("failed to parse ID token: %v", err) }