Routing (2)·续2

import { Agent, routeAgentRequest } from "agents";

export default {
    async fetch(request: Request, env: Env) {
        return (
            (await routeAgentRequest(request, env, {
                // Run before WebSocket connections
                onBeforeConnect: async (request) => {
                    const token = new URL(request.url).searchParams.get("token");
                    if (!(await verifyToken(token, env))) {
                        // Return a response to reject the connection
                        return new Response("Unauthorized", { status: 401 });
                    }
                    // Return nothing to allow the connection
                },
                // Run before HTTP requests
                onBeforeRequest: async (request) => {
                    const auth = request.headers.get("Authorization");
                    if (!auth || !(await verifyAuth(auth, env))) {
                        return new Response("Unauthorized", { status: 401 });
                    }
                },
                // Optional: prepend a prefix to agent instance names
                prefix: "user-",
            })) ?? new Response("Not found", { status: 404 })
        );
    },
} satisfies ExportedHandler<Env>;

Manual authentication

Check authentication before calling routeAgentRequest():

export default {
    async fetch(request, env) {
        const url = new URL(request.url);

// Protect agent routes
        if (url.pathname.startsWith("/agents/")) {
            const user = await authenticate(request, env);
            if (!user) {
                return new Response("Unauthorized", { status: 401 });
            }

// Optionally, enforce that users can only access their own agents
            const instanceName = url.pathname.split("/")[3];
            if (instanceName !== `user-${user.id}`) {
                return new Response("Forbidden", { status: 403 });
            }
        }

return (
            (await routeAgentRequest(request, env)) ??
            new Response("Not found", { status: 404 })
        );
    },
};
export default {
    async fetch(request: Request, env: Env) {
        const url = new URL(request.url);

// Protect agent routes
        if (url.pathname.startsWith("/agents/")) {
            const user = await authenticate(request, env);
            if (!user) {
                return new Response("Unauthorized", { status: 401 });
            }

// Optionally, enforce that users can only access their own agents
            const instanceName = url.pathname.split("/")[3];
            if (instanceName !== `user-${user.id}`) {
                return new Response("Forbidden", { status: 403 });
            }
        }

return (
            (await routeAgentRequest(request, env)) ??
            new Response("Not found", { status: 404 })
        );
    },
} satisfies ExportedHandler<Env>;

Using a framework (Hono)

If you are using a framework like Hono ↗︎, authenticate in middleware before calling the agent:

import { Agent, getAgentByName } from "agents";
import { Hono } from "hono";

const app = new Hono();

// Authentication middleware
app.use("/agents/*", async (c, next) => {
    const token = c.req.header("Authorization")?.replace("Bearer ", "");
    if (!token || !(await verifyToken(token, c.env))) {
        return c.json({ error: "Unauthorized" }, 401);
    }
    await next();
});

// Route to a specific agent
app.all("/agents/code-review/:id/*", async (c) => {
    const id = c.req.param("id");
    const agent = await getAgentByName(c.env.CodeReviewAgent, id);
    return agent.fetch(c.req.raw);
});

export default app;
import { Agent, getAgentByName } from "agents";
import { Hono } from "hono";

const app = new Hono<{ Bindings: Env }>();

// Authentication middleware
app.use("/agents/*", async (c, next) => {
    const token = c.req.header("Authorization")?.replace("Bearer ", "");
    if (!token || !(await verifyToken(token, c.env))) {
        return c.json({ error: "Unauthorized" }, 401);
    }
    await next();
});

// Route to a specific agent
app.all("/agents/code-review/:id/*", async (c) => {
    const id = c.req.param("id");
    const agent = await getAgentByName(c.env.CodeReviewAgent, id);
    return agent.fetch(c.req.raw);
});

export default app;

For WebSocket authentication patterns (tokens in URLs, JWT refresh), refer to Cross-domain authentication.

Troubleshooting

Agent namespace not found

The error message lists available agents. Check:

  1. Agent class is exported from your entry point.
  2. Class name in code matches class_name in wrangler.jsonc.
  3. URL uses correct kebab-case name.

Request returns 404

  1. Verify the URL pattern: /agents/{agent-name}/{instance-name}.
  2. Check that routeAgentRequest() is called before your 404 handler.
  3. Ensure the response from routeAgentRequest() is returned (not just called).

WebSocket connection fails

  1. Do not modify the response from routeAgentRequest() for WebSocket upgrades.
  2. Ensure CORS is enabled if connecting from a different origin.
  3. Check browser dev tools for the actual error.

basePath not working

  1. Ensure your Worker handles the custom path and forwards to the agent.
  2. Use getAgentByName() + agent.fetch(request) to forward requests.
  3. The agent parameter is still required but ignored when basePath is set.
  4. Check that the server-side route matches the client's basePath.

API reference

routeAgentRequest(request, env, options?)

Routes a request to the appropriate agent.

Parameter Type Description
request Request The incoming request
env Env Environment with agent bindings
options.cors boolean \| HeadersInit Enable CORS headers
options.props Record<string, unknown> Props passed to whichever agent handles request
options.locationHint string Preferred location for agent instances
options.jurisdiction string Data jurisdiction for agent instances
options.onBeforeConnect Function Callback before WebSocket connections
options.onBeforeRequest Function Callback before HTTP requests

Returns: Promise<Response | undefined> - Response if matched, undefined if no agent route.

getAgentByName(namespace, name, options?)

Get an agent instance by name for server-side RPC or request forwarding.

Parameter Type Description
namespace DurableObjectNamespace<T> Agent binding from env
name string Instance name
options.locationHint string Preferred location
options.jurisdiction string Data jurisdiction
options.props Record<string, unknown> Initialization properties for onStart
options.routingRetry object Retry configuration for transient Durable Object routing failures

Returns: Promise<DurableObjectStub<T>> - Typed stub for calling agent methods or forwarding requests.

useAgent(options) / AgentClient options

Client connection options for custom routing:

Option Type Description
agent string Agent class name (required)
name string Instance name (default: "default")
basePath string Full URL path - bypasses agent/name URL construction
path string Additional path to append to the URL
onIdentity (name, agent) => void Called when server sends identity
onIdentityChange (oldName, newName, oldAgent, newAgent) => void Called when identity changes on reconnect

Return value properties (React hook):

Property Type Description
name string Current instance name (reactive)
agent string Current agent class name (reactive)
identified boolean Whether identity has been received (reactive)
ready Promise<void> Resolves when identity is received

Agent.options (server)

Static options for agent configuration:

Option Type Default Description
hibernate boolean true Whether the agent should hibernate when inactive
sendIdentityOnConnect boolean true Whether to send identity to clients on connect
hungScheduleTimeoutSeconds number 30 Timeout before a running schedule is considered hung
class SecureAgent extends Agent {
    static options = { sendIdentityOnConnect: false };
}
class SecureAgent extends Agent {
    static options = { sendIdentityOnConnect: false };
}

Next steps

Client SDK

Connect from browsers with useAgent and AgentClient.

Cross-domain authentication

WebSocket authentication patterns.

Callable methods

RPC from clients over WebSocket.

Configuration

Set up agent bindings in wrangler.jsonc.

Was this helpful?

YesNo

On this page

Routing (2)·续2 - 图1Docs

{"@context":"https://schema.org","@type":"TechArticle","@id":"https://developers.cloudflare.com/agents/runtime/communication/routing/#page","headline":"Routing","description":"Route HTTP and WebSocket requests to Agents SDK instances using routeAgentRequest() and getAgentByName().","url":"https://developers.cloudflare.com/agents/runtime/communication/routing/","inLanguage":"en","image":"https://developers.cloudflare.com/agents/runtime/communication/routing/og.png?v=4f8fb7776b8e581c","dateModified":"2026-09-15","publisher":{"@type":"Organization","name":"Cloudflare","description":"One platform for your apps, agents, and workforce. Build, secure, and scale without managing infrastructure","url":"https://www.cloudflare.com/","sameAs":["https://github.com/cloudflare","https://www.linkedin.com/company/cloudflare","https://x.com/cloudflare"],"logo":{"@type":"ImageObject","url":"https://developers.cloudflare.com/logo.svg"},"address":{"@type":"PostalAddress","streetAddress":"101 Townsend St","addressLocality":"San Francisco","addressRegion":"CA","postalCode":"94107","addressCountry":"US"},"contactPoint":[{"@type":"ContactPoint","contactType":"Customer Support","url":"https://support.cloudflare.com/","availableLanguage":["English"]},{"@type":"ContactPoint","contactType":"Sales","url":"https://www.cloudflare.com/contact/","availableLanguage":["English"]}]},"isPartOf":{"@type":"WebSite","@id":"https://developers.cloudflare.com/#website","name":"Cloudflare Docs","url":"https://developers.cloudflare.com/"}}


description: Handle real-time WebSocket connections, messages, broadcasts, and lifecycle hooks in the Agents SDK. title: WebSockets image: https://developers.cloudflare.com/agents/runtime/communication/websockets/og.png?v=b59d4260b0dd4fe9


Skip to content

Documentation Index
Fetch the complete documentation index at: https://developers.cloudflare.com/agents/llms.txt
Use this file to discover all available pages before exploring further.