Skip to content

💡 Feature Request: CORS Support for api.trycloudflare.com/tunnel #1634

@MarketingPip

Description

@MarketingPip

Feature Request: CORS Support for api.trycloudflare.com/tunnel

Description

Currently, the api.trycloudflare.com/tunnel endpoint (used for Quick Tunnels / TryCloudflare) does not return Cross-Origin Resource Sharing (CORS) headers. This prevents developers from programmatically creating and managing ephemeral tunnels directly from browser-based environments (Web IDEs, browser consoles, or client-side admin dashboards) without using a custom proxy or a local cloudflared binary.

Adding Access-Control-Allow-Origin: * (or allowing specific origins) and supporting the OPTIONS preflight would allow for a new class of "Browser-to-Global" applications where a browser tab can act as a temporary origin.

Use Case

Developers often need to share a "Virtual File System" (VFS) or a local state directly from a browser tab to the public internet for debugging or temporary sharing. With CORS support, we could:

  1. Register a tunnel via fetch.
  2. Keep the tunnel alive using a polling heartbeat or WebSocket.
  3. Serve content directly from the browser's memory/VFS.

Proposed Implementation Examples

1. Registration (Fetch Example)

With CORS enabled, we could register a tunnel directly:

const response = await fetch("https://api.trycloudflare.com/tunnel", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ protocol: "http" })
});
const { result } = await response.json();
console.log(`Tunnel assigned: https://${result.hostname}`);

2. Keeping the Tunnel Alive (Polling Heartbeat)

Since browsers cannot always maintain a persistent binary socket like cloudflared, a polling mechanism could allow the browser to "announce" it is still active and update the served content:

const secret = result.secret;
const tunnelUrl = `https://${result.hostname}`;

// Heartbeat to keep the route active and update content
setInterval(async () => {
  await fetch(tunnelUrl, {
    method: "POST",
    headers: {
      "X-Tunnel-Secret": secret,
      "Content-Type": "text/plain"
    },
    body: "Current VFS State: " + new Date().toISOString(),
    mode: 'cors'
  });
}, 5000);

3. Real-time Streaming (WebSocket Example)

Ideally, if the Edge allowed WebSocket upgrades with the tunnel secret, we could stream data in real-time:

// This currently fails because native WebSockets can't send the X-Tunnel-Secret header.
// A potential fix would be allowing the secret in a query param for browser clients.
const socket = new WebSocket(`wss://region1.v2.argotunnel.com/?id=${result.id}&secret=${result.secret}`);

socket.onmessage = (event) => {
  // Respond to an incoming HTTP request from the internet
  const response = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<h1>Hello from Browser!</h1>";
  socket.send(response);
};

Requested Changes

  • Add Access-Control-Allow-Origin headers to https://api.trycloudflare.com/tunnel.
  • Allow X-Tunnel-Secret in the Access-Control-Allow-Headers list.
  • Consider a WebSocket-friendly handshake that doesn't require custom headers (e.g., via query parameters) for pure browser compatibility.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Priority: NormalMinor issue impacting one or more usersType: Feature RequestA big idea that would be split into smaller pieces

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions