website/src/content/docs/general/cors.mdx
Unlike stateless HTTP APIs that use CORS headers, Rivet Actors are stateful and support persistent WebSocket connections. Since WebSockets don't natively support CORS, we validate origins manually in the onBeforeConnect hook before connections may open.
To implement origin restrictions on Rivet Actors, use the onBeforeConnect hook to verify the request.
import { actor, UserError } from "rivetkit";
const ALLOWED_ORIGINS = [
"http://localhost:3000",
"https://myapp.com",
"https://www.myapp.com"
];
const myActor = actor({
state: { count: 0 },
onBeforeConnect: (c, params) => {
// Check if origin is allowed
//
// This works for both HTTP & WebSocket requests
const origin = c.request?.headers.get("origin") ?? "";
if (!ALLOWED_ORIGINS.includes(origin)) {
throw new UserError("Origin not allowed", { code: "origin_not_allowed" });
}
},
actions: {
increment: (c) => {
c.state.count++;
return c.state.count;
}
}
});
To catch the error on the client, use the following code:
import { createClient, ActorError } from "rivetkit/client";
import { actor, setup } from "rivetkit";
const myActor = actor({
state: { count: 0 },
actions: { increment: (c) => c.state.count++ }
});
const registry = setup({ use: { myActor } });
const client = createClient<typeof registry>("http://localhost:6420");
try {
const actorHandle = client.myActor.getOrCreate(["my-actor"]);
const conn = actorHandle.connect();
// Connection will be established or error will be thrown
await conn.increment();
} catch (error) {
if (error instanceof ActorError && error.code === "origin_not_allowed") {
console.error("Connection rejected: Origin not allowed");
}
}