Conversation
Linkup patch 1
Use API for TURN server credentials
There was a problem hiding this comment.
Pull Request Overview
This PR updates the WebRTC configuration to dynamically fetch TURN server credentials from the Metered API instead of using hardcoded credentials. The main changes include:
- Dynamic fetching of ICE servers with caching
- Environment variable configuration for the Metered API key
- Async handling in peer connection creation
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 5 comments.
| File | Description |
|---|---|
| frontend/src/config.ts | Added fetchIceServers function to dynamically fetch TURN credentials from Metered API with fallback to STUN servers |
| frontend/src/hooks/useWebRTC.ts | Updated createPeerConnection to be async, fetch ICE servers on demand with caching, and updated all call sites |
| frontend/.env.example | Added environment variable documentation for VITE_METERED_API_KEY |
| .github/workflows/deploy_front.yml | Added secret injection for the Metered API key in deployment workflow |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| export const METERED_API_URL = `https://linkup-ufazien.metered.live/api/v1/turn/credentials?apiKey=${METERED_API_KEY}`; | ||
|
|
||
| // Function to fetch TURN server credentials | ||
| export const fetchIceServers = async (): Promise<RTCIceServer[]> => { | ||
| try { | ||
| const response = await fetch(METERED_API_URL); |
There was a problem hiding this comment.
The API key is exposed in the URL query string. While this appears to be client-side code where the key must be public, consider if there are API rate limits or abuse concerns. The Metered API documentation should be checked to ensure this is the intended usage pattern. If the API supports it, consider using request headers for authentication instead.
| export const METERED_API_URL = `https://linkup-ufazien.metered.live/api/v1/turn/credentials?apiKey=${METERED_API_KEY}`; | |
| // Function to fetch TURN server credentials | |
| export const fetchIceServers = async (): Promise<RTCIceServer[]> => { | |
| try { | |
| const response = await fetch(METERED_API_URL); | |
| export const METERED_API_URL = 'https://linkup-ufazien.metered.live/api/v1/turn/credentials'; | |
| // Function to fetch TURN server credentials | |
| export const fetchIceServers = async (): Promise<RTCIceServer[]> => { | |
| try { | |
| const response = await fetch(METERED_API_URL, { | |
| headers: { | |
| 'Authorization': `Bearer ${METERED_API_KEY}` | |
| } | |
| }); |
| if (!iceServersRef.current) { | ||
| console.log('Fetching TURN server credentials...'); | ||
| iceServersRef.current = await fetchIceServers(); | ||
| console.log('ICE servers fetched:', iceServersRef.current); | ||
| } |
There was a problem hiding this comment.
Race condition: If createPeerConnection is called simultaneously for multiple peers before the first fetch completes, multiple concurrent fetchIceServers() calls will be made. Consider implementing a promise-based lock pattern or storing the promise itself to ensure only one fetch occurs. Example: if (!iceServersPromise) { iceServersPromise = fetchIceServers(); } iceServersRef.current = await iceServersPromise;
| export const RTC_CONFIG: RTCConfiguration = { | ||
| iceServers: [ | ||
| { | ||
| urls: 'stun:stun.relay.metered.ca:80' | ||
| }, | ||
| { | ||
| urls: 'turn:global.relay.metered.ca:80', | ||
| username: '81df41330ffff0c3d75e77ed', | ||
| credential: 'yn1jtZhMFeVgGmYo' | ||
| }, | ||
| { | ||
| urls: 'turn:global.relay.metered.ca:80?transport=tcp', | ||
| username: '81df41330ffff0c3d75e77ed', | ||
| credential: 'yn1jtZhMFeVgGmYo' | ||
| }, | ||
| { | ||
| urls: 'turn:global.relay.metered.ca:443', | ||
| username: '81df41330ffff0c3d75e77ed', | ||
| credential: 'yn1jtZhMFeVgGmYo' | ||
| }, | ||
| { | ||
| urls: 'turns:global.relay.metered.ca:443?transport=tcp', | ||
| username: '81df41330ffff0c3d75e77ed', | ||
| credential: 'yn1jtZhMFeVgGmYo' | ||
| urls: 'stun:stun.l.google.com:19302' | ||
| } | ||
| ] | ||
| }; |
There was a problem hiding this comment.
The RTC_CONFIG export is no longer used after switching to dynamic ICE server fetching. Consider removing this unused export to avoid confusion and maintain cleaner code.
| try { | ||
| const response = await fetch(METERED_API_URL); | ||
| if (!response.ok) { | ||
| throw new Error('Failed to fetch TURN credentials'); |
There was a problem hiding this comment.
The error message could be more descriptive by including the HTTP status code or response details. Consider: throw new Error(\Failed to fetch TURN credentials: ${response.status} ${response.statusText}`);`
| throw new Error('Failed to fetch TURN credentials'); | |
| throw new Error(`Failed to fetch TURN credentials: ${response.status} ${response.statusText}`); |
| env: | ||
| VITE_API_URL: https://videoo-call.onrender.com | ||
| VITE_WS_URL: wss://videoo-call.onrender.com | ||
| VITE_METERED_API_KEY: ${{ secrets.VITE_METERED_API_KEY }} |
There was a problem hiding this comment.
Extra whitespace between colon and value. Should be single space for consistency with other environment variables.
| VITE_METERED_API_KEY: ${{ secrets.VITE_METERED_API_KEY }} | |
| VITE_METERED_API_KEY: ${{ secrets.VITE_METERED_API_KEY }} |
This pull request updates the WebRTC configuration to dynamically fetch TURN server credentials from the Metered API, improving security and flexibility. It removes hardcoded credentials from the codebase and updates environment configuration and workflow files to support the new approach.
WebRTC Configuration & TURN Server Credentials
RTC_CONFIGwith logic to fetch credentials dynamically from the Metered API using theVITE_METERED_API_KEYenvironment variable inconfig.ts. This also introduces a fallback to Google's public STUN server if fetching fails.useWebRTChook to use the newfetchIceServersfunction for initializing peer connections, ensuring credentials are fetched once and cached for reuse. All peer connection creation logic now awaits the dynamic fetching of ICE servers. [1] [2] [3] [4] [5]Environment & Deployment Configuration
VITE_METERED_API_KEYto the.env.examplefile with instructions for obtaining the key, and clarified usage for local and production API URLs.