$apiKey, 'sub' => $identity, 'iat' => $now, 'nbf' => $now, 'exp' => $now + 3600, 'name' => $displayName, 'video' => [ 'roomJoin' => true, 'room' => $roomName, 'canPublish' => $grants['can_publish'] ?? true, 'canSubscribe' => $grants['can_subscribe'] ?? true, 'canPublishData' => $grants['can_publish_data'] ?? true, 'roomAdmin' => $grants['room_admin'] ?? false, ], ]; return $this->encodeJwt($payload, $apiSecret); } public function isConfigured(): bool { return filled(config('meet.media.livekit.url')) && filled(config('meet.media.livekit.api_key')) && filled(config('meet.media.livekit.api_secret')); } public function serverUrl(): string { return (string) config('meet.media.livekit.url'); } /** * @param array $payload */ protected function encodeJwt(array $payload, string $secret): string { $header = $this->base64UrlEncode(json_encode(['alg' => 'HS256', 'typ' => 'JWT'], JSON_THROW_ON_ERROR)); $body = $this->base64UrlEncode(json_encode($payload, JSON_THROW_ON_ERROR)); $signature = $this->base64UrlEncode( hash_hmac('sha256', "{$header}.{$body}", $secret, true) ); return "{$header}.{$body}.{$signature}"; } protected function base64UrlEncode(string $data): string { return rtrim(strtr(base64_encode($data), '+/', '-_'), '='); } }