diff --git a/.changes/jwt-video-grant-claim-names b/.changes/jwt-video-grant-claim-names new file mode 100644 index 000000000..46781ddf9 --- /dev/null +++ b/.changes/jwt-video-grant-claim-names @@ -0,0 +1 @@ +patch type="fixed" "`LiveKitVideoGrant` now reads the camelCase keys of the `video` claim (`roomJoin`, `canPublish`, and so on), so `TokenSourceResponse.jwtPayload?.video` returns the grants of a real LiveKit token instead of null fields" diff --git a/.changes/jwt-video-grant-missing-fields b/.changes/jwt-video-grant-missing-fields new file mode 100644 index 000000000..561ad3b45 --- /dev/null +++ b/.changes/jwt-video-grant-missing-fields @@ -0,0 +1 @@ +patch type="added" "`LiveKitVideoGrant` now decodes the remaining `video` claim fields: `canUpdateOwnMetadata`, `ingressAdmin`, `agent`, `canSubscribeMetrics`, `canManageAgentSession` and `destinationRoom`" diff --git a/lib/src/token_source/jwt.dart b/lib/src/token_source/jwt.dart index a2ef8b2ff..120808973 100644 --- a/lib/src/token_source/jwt.dart +++ b/lib/src/token_source/jwt.dart @@ -132,37 +132,26 @@ class LiveKitJwtPayload { /// LiveKit-specific video grants embedded within a JWT. @JsonSerializable() class LiveKitVideoGrant { + // Field names match the camelCase keys of the `video` claim that LiveKit + // server SDKs write, so they need no `@JsonKey` renames. final String? room; - - @JsonKey(name: 'room_create') final bool? roomCreate; - - @JsonKey(name: 'room_join') final bool? roomJoin; - - @JsonKey(name: 'room_list') final bool? roomList; - - @JsonKey(name: 'room_record') final bool? roomRecord; - - @JsonKey(name: 'room_admin') final bool? roomAdmin; - - @JsonKey(name: 'can_publish') final bool? canPublish; - - @JsonKey(name: 'can_subscribe') final bool? canSubscribe; - - @JsonKey(name: 'can_publish_data') final bool? canPublishData; - - @JsonKey(name: 'can_publish_sources') final List? canPublishSources; - + final bool? canUpdateOwnMetadata; + final bool? ingressAdmin; final bool? hidden; final bool? recorder; + final bool? agent; + final bool? canSubscribeMetrics; + final bool? canManageAgentSession; + final String? destinationRoom; const LiveKitVideoGrant({ this.room, @@ -175,8 +164,14 @@ class LiveKitVideoGrant { this.canSubscribe, this.canPublishData, this.canPublishSources, + this.canUpdateOwnMetadata, + this.ingressAdmin, this.hidden, this.recorder, + this.agent, + this.canSubscribeMetrics, + this.canManageAgentSession, + this.destinationRoom, }); factory LiveKitVideoGrant.fromJson(Map json) => _$LiveKitVideoGrantFromJson(json); diff --git a/lib/src/token_source/jwt.g.dart b/lib/src/token_source/jwt.g.dart index 3935f78e6..22078570c 100644 --- a/lib/src/token_source/jwt.g.dart +++ b/lib/src/token_source/jwt.g.dart @@ -8,30 +8,42 @@ part of 'jwt.dart'; LiveKitVideoGrant _$LiveKitVideoGrantFromJson(Map json) => LiveKitVideoGrant( room: json['room'] as String?, - roomCreate: json['room_create'] as bool?, - roomJoin: json['room_join'] as bool?, - roomList: json['room_list'] as bool?, - roomRecord: json['room_record'] as bool?, - roomAdmin: json['room_admin'] as bool?, - canPublish: json['can_publish'] as bool?, - canSubscribe: json['can_subscribe'] as bool?, - canPublishData: json['can_publish_data'] as bool?, - canPublishSources: (json['can_publish_sources'] as List?)?.map((e) => e as String).toList(), + roomCreate: json['roomCreate'] as bool?, + roomJoin: json['roomJoin'] as bool?, + roomList: json['roomList'] as bool?, + roomRecord: json['roomRecord'] as bool?, + roomAdmin: json['roomAdmin'] as bool?, + canPublish: json['canPublish'] as bool?, + canSubscribe: json['canSubscribe'] as bool?, + canPublishData: json['canPublishData'] as bool?, + canPublishSources: (json['canPublishSources'] as List?)?.map((e) => e as String).toList(), + canUpdateOwnMetadata: json['canUpdateOwnMetadata'] as bool?, + ingressAdmin: json['ingressAdmin'] as bool?, hidden: json['hidden'] as bool?, recorder: json['recorder'] as bool?, + agent: json['agent'] as bool?, + canSubscribeMetrics: json['canSubscribeMetrics'] as bool?, + canManageAgentSession: json['canManageAgentSession'] as bool?, + destinationRoom: json['destinationRoom'] as String?, ); Map _$LiveKitVideoGrantToJson(LiveKitVideoGrant instance) => { 'room': ?instance.room, - 'room_create': ?instance.roomCreate, - 'room_join': ?instance.roomJoin, - 'room_list': ?instance.roomList, - 'room_record': ?instance.roomRecord, - 'room_admin': ?instance.roomAdmin, - 'can_publish': ?instance.canPublish, - 'can_subscribe': ?instance.canSubscribe, - 'can_publish_data': ?instance.canPublishData, - 'can_publish_sources': ?instance.canPublishSources, + 'roomCreate': ?instance.roomCreate, + 'roomJoin': ?instance.roomJoin, + 'roomList': ?instance.roomList, + 'roomRecord': ?instance.roomRecord, + 'roomAdmin': ?instance.roomAdmin, + 'canPublish': ?instance.canPublish, + 'canSubscribe': ?instance.canSubscribe, + 'canPublishData': ?instance.canPublishData, + 'canPublishSources': ?instance.canPublishSources, + 'canUpdateOwnMetadata': ?instance.canUpdateOwnMetadata, + 'ingressAdmin': ?instance.ingressAdmin, 'hidden': ?instance.hidden, 'recorder': ?instance.recorder, + 'agent': ?instance.agent, + 'canSubscribeMetrics': ?instance.canSubscribeMetrics, + 'canManageAgentSession': ?instance.canManageAgentSession, + 'destinationRoom': ?instance.destinationRoom, }; diff --git a/test/token/token_source_test.dart b/test/token/token_source_test.dart index 18b8ce2af..251bf8fa2 100644 --- a/test/token/token_source_test.dart +++ b/test/token/token_source_test.dart @@ -166,13 +166,20 @@ void main() { attributes: {'role': 'host'}, video: { 'room': 'demo-room', - 'room_join': true, - 'room_create': true, - 'can_publish': true, - 'can_publish_data': true, - 'can_publish_sources': ['camera', 'screen'], + 'roomJoin': true, + 'roomCreate': true, + 'canPublish': true, + 'canSubscribe': false, + 'canPublishData': true, + 'canPublishSources': ['camera', 'screen'], + 'canUpdateOwnMetadata': true, + 'ingressAdmin': true, 'hidden': false, 'recorder': true, + 'agent': true, + 'canSubscribeMetrics': true, + 'canManageAgentSession': false, + 'destinationRoom': 'other-room', }, roomConfig: { 'agents': [ @@ -205,10 +212,17 @@ void main() { expect(grant.roomJoin, isTrue); expect(grant.roomCreate, isTrue); expect(grant.canPublish, isTrue); + expect(grant.canSubscribe, isFalse); expect(grant.canPublishData, isTrue); expect(grant.canPublishSources, ['camera', 'screen']); + expect(grant.canUpdateOwnMetadata, isTrue); + expect(grant.ingressAdmin, isTrue); expect(grant.hidden, isFalse); expect(grant.recorder, isTrue); + expect(grant.agent, isTrue); + expect(grant.canSubscribeMetrics, isTrue); + expect(grant.canManageAgentSession, isFalse); + expect(grant.destinationRoom, 'other-room'); final config = payload.roomConfiguration; expect(config, isNotNull); @@ -509,7 +523,7 @@ String _generateToken({ video ?? { 'room': 'test-room', - 'room_join': true, + 'roomJoin': true, }, };