wip use another scheme for LiveKit token auth

This commit is contained in:
lebaudantoine
2026-08-02 18:59:02 +02:00
parent 11c331dfa7
commit 1270885132
9 changed files with 128 additions and 59 deletions
+9 -2
View File
@@ -9,6 +9,8 @@ from rest_framework import authentication, exceptions
UserModel = get_user_model()
LIVEKIT_AUTH_SCHEME = "X-LiveKit-Token"
class LiveKitTokenAuthentication(authentication.BaseAuthentication):
"""Authenticate using LiveKit token and load the associated Django user."""
@@ -20,9 +22,14 @@ class LiveKitTokenAuthentication(authentication.BaseAuthentication):
return None # No authentication attempted
parts = auth_header.split()
if len(parts) != 2 or parts[0].lower() != "bearer":
if not parts or parts[0].lower() != LIVEKIT_AUTH_SCHEME.lower():
# Not our scheme (e.g. "Bearer <user access token>"): defer, another
# backend may recognize it.
return None
if len(parts) != 2:
raise exceptions.AuthenticationFailed(
"Authorization header must be: Bearer <token>"
f"Authorization header must be: {LIVEKIT_AUTH_SCHEME} <token>"
)
token = parts[1]
@@ -87,7 +87,7 @@ def test_mute_participant_with_livekit_token_for_this_room(mock_livekit_client):
url,
{"participant_identity": str(uuid4()), "track_sid": "test-track-sid"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_200_OK
@@ -113,7 +113,7 @@ def test_mute_participant_with_livekit_token_for_another_room_forbidden(
url,
{"participant_identity": str(uuid4()), "track_sid": "test-track-sid"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@@ -153,7 +153,7 @@ def test_mute_participant_everyone_can_mute_disabled_blocks_non_admin(
url,
{"participant_identity": str(uuid4()), "track_sid": "test-track-sid"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@@ -300,7 +300,7 @@ def test_mute_participant_admin_with_token_for_this_room(mock_livekit_client):
url,
{"participant_identity": str(uuid4()), "track_sid": "test-track-sid"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_200_OK
@@ -330,7 +330,7 @@ def test_mute_participant_admin_with_token_for_another_room(mock_livekit_client)
url,
{"participant_identity": str(uuid4()), "track_sid": "test-track-sid"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@@ -361,7 +361,7 @@ def test_mute_participant_admin_token_replayed_does_not_grant_admin(
url,
{"participant_identity": str(uuid4()), "track_sid": "test-track-sid"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@@ -381,7 +381,7 @@ def test_mute_participant_livekit_token_triggers_presence_check(mock_livekit_cli
url,
{"participant_identity": str(uuid4()), "track_sid": "test-track-sid"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_200_OK
@@ -412,7 +412,7 @@ def test_mute_participant_livekit_token_presence_check_returns_participant(
url,
{"participant_identity": str(uuid4()), "track_sid": "test-track-sid"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_200_OK
@@ -440,7 +440,7 @@ def test_mute_participant_livekit_token_presence_check_participant_not_found(
url,
{"participant_identity": str(uuid4()), "track_sid": "test-track-sid"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@@ -469,7 +469,7 @@ def test_mute_participant_livekit_token_presence_check_twirp_error_forbidden(
url,
{"participant_identity": str(uuid4()), "track_sid": "test-track-sid"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@@ -1020,3 +1020,5 @@ def test_remove_participant_not_found(mock_livekit_client):
assert response.data == {"error": "Participant not found"}
mock_livekit_client.aclose.assert_called_once()
# todo - try to pass another scheme to make sure it defers to the next auth
@@ -69,7 +69,10 @@ def test_toggle_hand_raise_success(mock_livekit_client, room, token):
client = APIClient()
url = reverse("rooms-toggle-hand", kwargs={"pk": room.id})
response = client.post(
url, {"raised": True}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}"
url,
{"raised": True},
format="json",
HTTP_AUTHORIZATION=f"X-LiveKit-token {token}",
)
assert response.status_code == status.HTTP_200_OK
@@ -84,7 +87,10 @@ def test_toggle_hand_lower_success(mock_livekit_client, room, token):
client = APIClient()
url = reverse("rooms-toggle-hand", kwargs={"pk": room.id})
response = client.post(
url, {"raised": False}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}"
url,
{"raised": False},
format="json",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_200_OK
@@ -101,7 +107,10 @@ def test_toggle_hand_raise_sets_timestamp(mock_livekit_client, room, token):
client = APIClient()
url = reverse("rooms-toggle-hand", kwargs={"pk": room.id})
response = client.post(
url, {"raised": True}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}"
url,
{"raised": True},
format="json",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_200_OK
@@ -117,7 +126,10 @@ def test_toggle_hand_identity_derived_from_token(
client = APIClient()
url = reverse("rooms-toggle-hand", kwargs={"pk": room.id})
client.post(
url, {"raised": True}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}"
url,
{"raised": True},
format="json",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
call_kwargs = mock_livekit_client.room.update_participant.call_args
@@ -128,7 +140,9 @@ def test_toggle_hand_missing_raised_field(room, token):
"""Test toggle hand with missing raised field returns 400."""
client = APIClient()
url = reverse("rooms-toggle-hand", kwargs={"pk": room.id})
response = client.post(url, {}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}")
response = client.post(
url, {}, format="json", HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}"
)
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert "raised" in response.data
@@ -142,7 +156,7 @@ def test_toggle_hand_invalid_raised_field(room, token):
url,
{"raised": "not-a-boolean"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_400_BAD_REQUEST
@@ -166,7 +180,10 @@ def test_toggle_hand_forbidden_token_for_wrong_room(user):
client = APIClient()
url = reverse("rooms-toggle-hand", kwargs={"pk": target_room.id})
response = client.post(
url, {"raised": True}, format="json", HTTP_AUTHORIZATION=f"Bearer {wrong_token}"
url,
{"raised": True},
format="json",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {wrong_token}",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@@ -181,7 +198,10 @@ def test_toggle_hand_unexpected_twirp_error(mock_livekit_client, room, token):
client = APIClient()
url = reverse("rooms-toggle-hand", kwargs={"pk": room.id})
response = client.post(
url, {"raised": True}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}"
url,
{"raised": True},
format="json",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR
@@ -200,7 +220,7 @@ def test_toggle_hand_raise_success_anonymous(
url,
{"raised": True},
format="json",
HTTP_AUTHORIZATION=f"Bearer {anonymous_token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {anonymous_token}",
)
assert response.status_code == status.HTTP_200_OK
@@ -220,7 +240,7 @@ def test_toggle_hand_lower_success_anonymous(
url,
{"raised": False},
format="json",
HTTP_AUTHORIZATION=f"Bearer {anonymous_token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {anonymous_token}",
)
assert response.status_code == status.HTTP_200_OK
@@ -240,7 +260,7 @@ def test_toggle_hand_identity_derived_from_token_anonymous(
url,
{"raised": True},
format="json",
HTTP_AUTHORIZATION=f"Bearer {anonymous_token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {anonymous_token}",
)
call_kwargs = mock_livekit_client.room.update_participant.call_args
@@ -257,7 +277,10 @@ def test_rename_participant_success(mock_livekit_client, room, token):
client = APIClient()
url = reverse("rooms-rename", kwargs={"pk": room.id})
response = client.post(
url, {"name": "John Doe"}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}"
url,
{"name": "John Doe"},
format="json",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_200_OK
@@ -272,7 +295,10 @@ def test_rename_participant_sets_correct_name(mock_livekit_client, room, token):
client = APIClient()
url = reverse("rooms-rename", kwargs={"pk": room.id})
client.post(
url, {"name": "Jane Doe"}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}"
url,
{"name": "Jane Doe"},
format="json",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
call_kwargs = mock_livekit_client.room.update_participant.call_args
@@ -286,7 +312,10 @@ def test_rename_participant_uses_identity_from_token(
client = APIClient()
url = reverse("rooms-rename", kwargs={"pk": room.id})
client.post(
url, {"name": "John Doe"}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}"
url,
{"name": "John Doe"},
format="json",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
call_kwargs = mock_livekit_client.room.update_participant.call_args
@@ -298,7 +327,7 @@ def test_rename_participant_empty_name(room, token):
client = APIClient()
url = reverse("rooms-rename", kwargs={"pk": room.id})
response = client.post(
url, {"name": ""}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}"
url, {"name": ""}, format="json", HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}"
)
assert response.status_code == status.HTTP_400_BAD_REQUEST
@@ -309,7 +338,9 @@ def test_rename_participant_missing_name(room, token):
"""Test rename with missing name field returns 400."""
client = APIClient()
url = reverse("rooms-rename", kwargs={"pk": room.id})
response = client.post(url, {}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}")
response = client.post(
url, {}, format="json", HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}"
)
assert response.status_code == status.HTTP_400_BAD_REQUEST
assert "name" in response.data
@@ -320,7 +351,10 @@ def test_rename_participant_name_too_long(room, token):
client = APIClient()
url = reverse("rooms-rename", kwargs={"pk": room.id})
response = client.post(
url, {"name": "a" * 256}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}"
url,
{"name": "a" * 256},
format="json",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_400_BAD_REQUEST
@@ -348,7 +382,7 @@ def test_rename_participant_forbidden_token_for_wrong_room(user):
url,
{"name": "John Doe"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {wrong_token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {wrong_token}",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@@ -363,7 +397,10 @@ def test_rename_participant_unexpected_twirp_error(mock_livekit_client, room, to
client = APIClient()
url = reverse("rooms-rename", kwargs={"pk": room.id})
response = client.post(
url, {"name": "John Doe"}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}"
url,
{"name": "John Doe"},
format="json",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_500_INTERNAL_SERVER_ERROR
@@ -382,7 +419,7 @@ def test_rename_participant_success_anonymous(
url,
{"name": "Guest User"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {anonymous_token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {anonymous_token}",
)
assert response.status_code == status.HTTP_200_OK
@@ -402,7 +439,7 @@ def test_rename_participant_uses_identity_from_token_anonymous(
url,
{"name": "Guest User"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {anonymous_token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {anonymous_token}",
)
call_kwargs = mock_livekit_client.room.update_participant.call_args
@@ -419,7 +456,7 @@ def test_rename_participant_sets_correct_name_anonymous(
url,
{"name": "Guest User"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {anonymous_token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {anonymous_token}",
)
call_kwargs = mock_livekit_client.room.update_participant.call_args
@@ -436,7 +473,7 @@ def test_rename_participant_forbidden_anonymous_token_for_wrong_room(anonymous_t
url,
{"name": "Guest User"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {anonymous_token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {anonymous_token}",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@@ -462,7 +499,7 @@ def test_toggle_hand_expired_token(room, expired_token):
url,
{"raised": True},
format="json",
HTTP_AUTHORIZATION=f"Bearer {expired_token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {expired_token}",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@@ -476,7 +513,7 @@ def test_rename_participant_expired_token(room, expired_token):
url,
{"name": "John Doe"},
format="json",
HTTP_AUTHORIZATION=f"Bearer {expired_token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {expired_token}",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@@ -490,7 +527,7 @@ def test_toggle_hand_malformed_token(room):
url,
{"raised": True},
format="json",
HTTP_AUTHORIZATION="Bearer this-is-not-a-valid-jwt",
HTTP_AUTHORIZATION="X-LiveKit-Token this-is-not-a-valid-jwt",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@@ -504,7 +541,10 @@ def test_toggle_hand_room_not_found(user):
client = APIClient()
url = reverse("rooms-toggle-hand", kwargs={"pk": non_existent_room_id})
response = client.post(
url, {"raised": True}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}"
url,
{"raised": True},
format="json",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_404_NOT_FOUND
@@ -519,7 +559,10 @@ def test_toggle_hand_participant_not_found(mock_livekit_client, room, token):
client = APIClient()
url = reverse("rooms-toggle-hand", kwargs={"pk": room.id})
response = client.post(
url, {"raised": True}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}"
url,
{"raised": True},
format="json",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_404_NOT_FOUND
@@ -536,7 +579,7 @@ def test_rename_participant_malformed_token(room):
url,
{"name": "John Doe"},
format="json",
HTTP_AUTHORIZATION="Bearer this-is-not-a-valid-jwt",
HTTP_AUTHORIZATION="X-LiveKit-Token this-is-not-a-valid-jwt",
)
assert response.status_code == status.HTTP_403_FORBIDDEN
@@ -550,7 +593,10 @@ def test_rename_participant_room_not_found(user):
client = APIClient()
url = reverse("rooms-rename", kwargs={"pk": non_existent_room_id})
response = client.post(
url, {"name": "John Doe"}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}"
url,
{"name": "John Doe"},
format="json",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_404_NOT_FOUND
@@ -565,10 +611,15 @@ def test_rename_participant_not_found(mock_livekit_client, room, token):
client = APIClient()
url = reverse("rooms-rename", kwargs={"pk": room.id})
response = client.post(
url, {"name": "John Doe"}, format="json", HTTP_AUTHORIZATION=f"Bearer {token}"
url,
{"name": "John Doe"},
format="json",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {token}",
)
assert response.status_code == status.HTTP_404_NOT_FOUND
assert response.data == {"error": "Participant not found"}
mock_livekit_client.aclose.assert_called_once()
# todo - try to pass another scheme to make sure it defers to the next auth
@@ -110,7 +110,7 @@ def test_start_subtitle_invalid_token():
response = client.post(
f"/api/v1.0/rooms/{room.id}/start-subtitle/",
{},
HTTP_AUTHORIZATION="Bearer invalid-token",
HTTP_AUTHORIZATION="X-LiveKit-Token invalid-token",
)
assert response.status_code == 403
@@ -128,7 +128,7 @@ def test_start_subtitle_disabled_by_default(mock_livekit_token):
response = client.post(
f"/api/v1.0/rooms/{room.id}/start-subtitle/",
{},
HTTP_AUTHORIZATION=f"Bearer {mock_livekit_token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {mock_livekit_token}",
)
assert response.status_code == 404
@@ -148,7 +148,7 @@ def test_start_subtitle_valid_token(
response = client.post(
f"/api/v1.0/rooms/{room.id}/start-subtitle/",
{},
HTTP_AUTHORIZATION=f"Bearer {mock_livekit_token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {mock_livekit_token}",
)
assert response.status_code == 200
@@ -178,7 +178,7 @@ def test_start_subtitle_twirp_error(
response = client.post(
f"/api/v1.0/rooms/{room.id}/start-subtitle/",
{},
HTTP_AUTHORIZATION=f"Bearer {mock_livekit_token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {mock_livekit_token}",
)
assert response.status_code == 500
@@ -198,7 +198,7 @@ def test_start_subtitle_wrong_room(settings, mock_livekit_token):
response = client.post(
f"/api/v1.0/rooms/{room.id}/start-subtitle/",
{},
HTTP_AUTHORIZATION=f"Bearer {mock_livekit_token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {mock_livekit_token}",
)
assert response.status_code == 403
@@ -219,10 +219,12 @@ def test_start_subtitle_wrong_signature(settings, mock_livekit_token):
response = client.post(
f"/api/v1.0/rooms/{room.id}/start-subtitle/",
{},
HTTP_AUTHORIZATION=f"Bearer {mock_livekit_token}",
HTTP_AUTHORIZATION=f"X-LiveKit-Token {mock_livekit_token}",
)
assert response.status_code == 403
assert response.json() == {
"detail": "Invalid LiveKit token: Signature verification failed"
}
# todo - try to pass another scheme to make sure it defers to the next auth
@@ -10,6 +10,7 @@ import { useIsAdminOrOwner } from '../livekit/hooks/useIsAdminOrOwner'
import { useCallback } from 'react'
import { reportError } from '@/features/analytics/telemetry'
import { getLiveKitAuthHeaders } from '../utils/getLiveKitAuthHeaders'
export const useMuteParticipant = () => {
const apiRoomData = useRoomData()
@@ -40,7 +41,7 @@ export const useMuteParticipant = () => {
}
const headers = !isAdminOrOwner
? { Authorization: `Bearer ${apiRoomData.livekit.token}` }
? getLiveKitAuthHeaders(apiRoomData.livekit.token)
: undefined
let response
@@ -1,5 +1,6 @@
import { fetchApi } from '@/api/fetchApi'
import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData'
import { getLiveKitAuthHeaders } from '../utils/getLiveKitAuthHeaders'
export const useRenameParticipant = () => {
const data = useRoomData()
@@ -15,11 +16,10 @@ export const useRenameParticipant = () => {
throw new Error('LiveKit token is not available')
}
const headers = getLiveKitAuthHeaders(token)
return fetchApi(`rooms/${data.id}/rename/`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
},
headers,
body: JSON.stringify({
name,
}),
@@ -1,5 +1,6 @@
import { fetchApi } from '@/api/fetchApi'
import { useRoomData } from '@/features/rooms/livekit/hooks/useRoomData'
import { getLiveKitAuthHeaders } from '../utils/getLiveKitAuthHeaders'
export const useRaiseHand = () => {
const data = useRoomData()
@@ -15,11 +16,10 @@ export const useRaiseHand = () => {
throw new Error('LiveKit token is not available')
}
const headers = getLiveKitAuthHeaders(token)
return fetchApi(`rooms/${data.id}/toggle-hand/`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
},
headers,
body: JSON.stringify({
raised,
}),
@@ -0,0 +1,7 @@
const LIVEKIT_AUTH_SCHEME = 'X-LiveKit-Token'
export const getLiveKitAuthHeaders = (token: string) => {
return {
Authorization: `${LIVEKIT_AUTH_SCHEME} ${token}`,
}
}
@@ -2,6 +2,7 @@ import { useMutation, type UseMutationOptions } from '@tanstack/react-query'
import { fetchApi } from '@/api/fetchApi'
import type { ApiError } from '@/api/ApiError'
import type { ApiRoom } from '@/features/rooms/api/ApiRoom'
import { getLiveKitAuthHeaders } from '@/features/rooms/utils/getLiveKitAuthHeaders'
export interface StartSubtitleParams {
id: string
@@ -14,9 +15,7 @@ const startSubtitle = ({
}: StartSubtitleParams): Promise<ApiRoom> => {
return fetchApi(`rooms/${id}/start-subtitle/`, {
method: 'POST',
headers: {
Authorization: `Bearer ${token}`,
},
headers: getLiveKitAuthHeaders(token),
})
}