Skip to content

Commit 25a2868

Browse files
committed
fix: ensure we don't reject tokens with unknown fields
1 parent ef3bb65 commit 25a2868

2 files changed

Lines changed: 45 additions & 1 deletion

File tree

auth/grants.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,12 @@ var tokenMarshaler = protojson.MarshalOptions{
3535
EmitDefaultValues: false,
3636
}
3737

38+
// tokenUnmarshaler discards unknown fields so that older servers can accept
39+
// tokens issued by newer clients that include fields the server does not yet know about.
40+
var tokenUnmarshaler = protojson.UnmarshalOptions{
41+
DiscardUnknown: true,
42+
}
43+
3844
var ErrSensitiveCredentials = errors.New("room configuration should not contain sensitive credentials")
3945

4046
func (c *RoomConfiguration) Clone() *RoomConfiguration {
@@ -49,7 +55,7 @@ func (c *RoomConfiguration) MarshalJSON() ([]byte, error) {
4955
}
5056

5157
func (c *RoomConfiguration) UnmarshalJSON(data []byte) error {
52-
return protojson.Unmarshal(data, (*livekit.RoomConfiguration)(c))
58+
return tokenUnmarshaler.Unmarshal(data, (*livekit.RoomConfiguration)(c))
5359
}
5460

5561
// CheckCredentials checks if the room configuration contains sensitive credentials

auth/verifier_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ import (
1818
"testing"
1919
"time"
2020

21+
"github.com/go-jose/go-jose/v3"
2122
"github.com/go-jose/go-jose/v3/json"
23+
"github.com/go-jose/go-jose/v3/jwt"
2224
"github.com/stretchr/testify/require"
2325

2426
"github.com/livekit/protocol/auth"
@@ -95,6 +97,42 @@ func TestVerifier(t *testing.T) {
9597
require.EqualValues(t, attrs, decoded.Attributes)
9698
})
9799

100+
t.Run("unknown roomConfig fields are ignored for forward compatibility", func(t *testing.T) {
101+
// Simulate a token issued by a newer client whose RoomConfiguration includes
102+
// a field this server's proto does not yet know about. The server should
103+
// still accept the token rather than failing with `unknown field`.
104+
sig, err := jose.NewSigner(
105+
jose.SigningKey{Algorithm: jose.HS256, Key: []byte(secret)},
106+
(&jose.SignerOptions{}).WithType("JWT"),
107+
)
108+
require.NoError(t, err)
109+
110+
claims := map[string]interface{}{
111+
"iss": apiKey,
112+
"sub": "me",
113+
"nbf": jwt.NewNumericDate(time.Now()),
114+
"exp": jwt.NewNumericDate(time.Now().Add(time.Minute)),
115+
"video": map[string]interface{}{
116+
"roomJoin": true,
117+
"room": "myroom",
118+
},
119+
"roomConfig": map[string]interface{}{
120+
"name": "myroom",
121+
"someFutureFieldName": "future-value",
122+
},
123+
}
124+
token, err := jwt.Signed(sig).Claims(claims).CompactSerialize()
125+
require.NoError(t, err)
126+
127+
v, err := auth.ParseAPIToken(token)
128+
require.NoError(t, err)
129+
130+
_, decoded, err := v.Verify(secret)
131+
require.NoError(t, err)
132+
require.NotNil(t, decoded.RoomConfig)
133+
require.Equal(t, "myroom", decoded.RoomConfig.Name)
134+
})
135+
98136
t.Run("nil permissions are handled", func(t *testing.T) {
99137
grant := &auth.VideoGrant{
100138
Room: "myroom",

0 commit comments

Comments
 (0)