Sign In
More

Cross-Origin Resource Sharing

Cross-Origin Resource Sharing (CORS) is a security mechanism that allows a web application running at one origin to access resources from a different origin. Without CORS, browsers block cross-origin HTTP requests by default as a security measure.

You'll need to configure CORS when:

  • Local Development: You're developing locally and your client runs on a different port than your actor service
  • Different Domain: Your frontend application is hosted on a different domain than your actor service

Registry-Level CORS

Configure CORS directly in your registry setup for applications that do not require configuring CORS on their own endpoints.

server.ts
import { registry } from "./registry";

const { client, serve } = registry.createServer({
	cors: {
		origin: "https://yourdomain.com",
	}
});

serve();

Configuration Options

origin

string | string[] | (origin: string) => boolean | string

Specifies which domains can access your resources:

server.ts
// Single domain
origin: "https://example.com"

// Multiple domains
origin: ["https://app.com", "https://admin.com"]

// Dynamic validation
origin: (origin) => {
  return origin?.endsWith('.example.com') ? origin : false;
}

// All domains (not recommended for production)
origin: "*"

allowMethods

string[]

HTTP methods clients are allowed to use:

TypeScript
allowMethods: ["GET", "POST", "OPTIONS"]  // Common for Rivet

allowHeaders

string[]

Headers that clients can send in requests:

TypeScript
allowHeaders: [
  "Authorization",           // Your auth headers
  "Content-Type",           // Standard content type
  "X-API-Key",              // Custom API key header
  ...ALLOWED_PUBLIC_HEADERS // Required Rivet headers
]

credentials

boolean

Whether to allow credentials (cookies, auth headers):

TypeScript
credentials: true  // Required for authentication

When credentials: true, you cannot use origin: "*". Specify exact origins instead.

maxAge

number

How long browsers cache CORS preflight responses (in seconds):

TypeScript
maxAge: 600  // Cache for 10 minutes

exposeHeaders

string[]

Server headers that browsers can access:

TypeScript
exposeHeaders: ["Content-Length", "X-Request-Id"]

Router-Level CORS

For applications that need to expose their own routes, configure CORS at the router level:

import { registry } from "./registry";
import { Hono } from "hono";
import { cors } from "hono/cors";
import { ALLOWED_PUBLIC_HEADERS } from "@rivetkit/actor";

const { serve } = registry.createServer();
const app = new Hono();

app.use("*", cors({
  origin: ["http://localhost:3000", "https://myapp.com"],
  allowHeaders: [
    "Authorization", 
    "Content-Type",
    ...ALLOWED_PUBLIC_HEADERS
  ],
}));

serve(app);

Required Headers for Rivet

Rivet requires specific headers for communication. Always include ALLOWED_PUBLIC_HEADERS:

server.ts
import { ALLOWED_PUBLIC_HEADERS } from "@rivetkit/actor";

const corsConfig = {
  allowHeaders: [
    "X-Foo-Bar",               // Whatever headers you need to configure
    ...ALLOWED_PUBLIC_HEADERS  // Required Rivet headers
  ]
};

These are automatically configured if using registry.runServer({ cors }).

Without ALLOWED_PUBLIC_HEADERS, Rivet clients won't be able to communicate with your actors from the browser.

Development vs Production

Development Setup

For local development, allow localhost origins:

TypeScript
const isDev = process.env.NODE_ENV !== "production";

const corsConfig = {
  origin: isDev 
    ? ["http://localhost:3000", "http://localhost:5173"] 
    : ["https://myapp.com"],
  allowHeaders: ["Authorization", ...ALLOWED_PUBLIC_HEADERS],
  credentials: true,
};

Production Setup

For production, be restrictive with origins:

TypeScript
const corsConfig = {
  origin: [
    "https://myapp.com",
    "https://www.myapp.com",
    "https://admin.myapp.com"
  ],
  allowHeaders: ["Authorization", ...ALLOWED_PUBLIC_HEADERS],
  credentials: true,
  maxAge: 3600, // Cache for 1 hour
};

Troubleshooting

Common CORS Errors

"Access to fetch blocked by CORS policy"

  • Add your frontend's origin to the origin list
  • Ensure ALLOWED_PUBLIC_HEADERS are included in allowHeaders

"Request header not allowed"

  • Add the missing header to allowHeaders
  • Include ALLOWED_PUBLIC_HEADERS in your configuration

"Credentials mode mismatch"

  • Set credentials: true in CORS config
  • Cannot use origin: "*" with credentials
Suggest changes to this page