HTTP Routes
Colyseus provides two ways to add HTTP endpoints to your server:
- API Routes (recommended): Type-safe, with validation, middleware, frontend SDK integration, and visual testing via the Playground.
- Express: Use if you rely on existing Express middleware or libraries.
API Routes
Define type-safe HTTP endpoints using createEndpoint and createRouter.
import { defineServer, createEndpoint, createRouter } from "colyseus";
import { z } from "zod";
const getProfile = createEndpoint("/profile/:id", {
method: "GET",
query: z.object({ include: z.string().optional() }),
}, async (ctx) => {
return {
id: ctx.params.id,
include: ctx.query.include,
};
});
const updateProfile = createEndpoint("/profile/:id", {
method: "POST",
body: z.object({ name: z.string() }),
}, async (ctx) => {
ctx.setStatus(201);
return { id: ctx.params.id, name: ctx.body.name };
});
const server = defineServer({
routes: createRouter({
getProfile,
updateProfile,
})
});Middleware
Use createMiddleware to share logic across endpoints. The returned context is merged into ctx.context.
import { createEndpoint, createMiddleware } from "colyseus";
const auth = createMiddleware(async (ctx) => {
const token = ctx.headers.get("authorization");
if (!token) throw ctx.error("UNAUTHORIZED", { message: "Missing token" });
return { userId: "user-123" };
});
export const secureEndpoint = createEndpoint("/secure", {
method: "GET",
use: [auth],
}, async (ctx) => {
ctx.setHeader("X-User", ctx.context.userId);
ctx.setCookie("session", "abc", { httpOnly: true });
return { ok: true, userId: ctx.context.userId };
});JWT Authentication
For JWT-based auth, @colyseus/auth exports auth.middleware(), a middleware that verifies the Authorization: Bearer <token> header and exposes the decoded payload on ctx.context.auth. It’s the canonical way to gate an endpoint behind a logged-in user.
import { createEndpoint } from "colyseus";
import { auth } from "@colyseus/auth";
export const profile = createEndpoint("/profile", {
method: "GET",
use: [auth.middleware()],
}, async (ctx) => {
return { user: ctx.context.auth };
});When @colyseus/database is in use, auth.middleware() is revocation-aware automatically. db.auth.ban(userId) and db.auth.bumpTokenVersion(userId) both invalidate live JWTs at the token layer (no per-route check needed). See Database → Authentication.
See Authentication → HTTP Middleware for the dual Express/createEndpoint modes, and Auth Module for backend setup.
Basic Authentication
basicAuth is a built-in middleware for HTTP Basic Auth. Drop it into any
endpoint’s use: array to gate it behind the browser’s native credentials
prompt.
import { createEndpoint, basicAuth } from "colyseus";
export const adminStats = createEndpoint("/admin-stats", {
method: "GET",
use: [ basicAuth({ users: { admin: "s3cret" } }) ],
}, async (ctx) => {
return { onlineUsers: 123 };
});A common use is protecting the Playground and
Monitor in production. Both accept a use: array:
import { defineServer, createRouter, basicAuth } from "colyseus";
import { playground } from "@colyseus/playground";
import { monitor } from "@colyseus/monitor";
const guard = basicAuth({ users: { admin: "s3cret" } });
const server = defineServer({
routes: createRouter({
...playground({ use: [guard] }),
...monitor({ use: [guard] }),
})
});Options
| Option | Description |
|---|---|
users | Record<string, string> mapping username → password. The common static case. |
validate | (username, password) => boolean | Promise<boolean>: custom/DB-backed check. Takes precedence over users. |
realm | Label shown in the browser prompt. Default "Restricted". |
On a missing or invalid credential the middleware responds 401 with a
WWW-Authenticate: Basic header, so browsers show the native login dialog.
Passwords are compared in constant time. You must provide at least one of
users or validate.
Endpoint Options
createEndpoint(path, options, handler) accepts the following options:
| Option | Description |
|---|---|
method | HTTP method string or array (e.g. "GET" or ["GET", "POST"]). |
body | Zod schema for request body validation. Invalid bodies return 400. |
query | Zod schema for query string validation. Invalid queries return 400. |
use | Array of middlewares created with createMiddleware. |
requireHeaders | When true, requires headers when calling the endpoint as a function. |
requireRequest | When true, requires a request object when calling the endpoint as a function. |
metadata.scope | "rpc" (default): available to RPC client. "server": routed and callable directly, hidden from the typed RPC client. "http": routed only. |
metadata.allowedMediaTypes | Restricts accepted Content-Type values for this endpoint. |
Handler Context
The handler signature is async (ctx) => response.
Properties
| Property | Description |
|---|---|
ctx.request | The raw Request object (when running via HTTP). |
ctx.headers | Headers instance for the incoming request. |
ctx.body | Parsed and validated request body. |
ctx.query | Parsed and validated query string. |
ctx.params | Route parameters (e.g. :id, **:name). |
ctx.method | HTTP method (useful for multi-method endpoints). |
ctx.context | Merged middleware context. |
Methods
| Method | Description |
|---|---|
ctx.setStatus(status) | Override the default success status code. |
ctx.error(codeOrStatus, data?, headers?) | Throw an API error. |
ctx.redirect(url) | Throw a redirect response. |
ctx.json(data) | Return a JSON response. |
ctx.setHeader(name, value) | Set a response header. |
ctx.setCookie(name, value, options?) | Set a response cookie. |
ctx.getCookie(name) | Read a request cookie. |
ctx.setSignedCookie(name, value, secret, options?) | Set a signed cookie. |
ctx.getSignedCookie(name, secret) | Read a signed cookie. |
Express Routes
Use Express if you rely on existing Express middleware or libraries.
import { defineServer } from "colyseus";
import express from "express";
const server = defineServer({
// ...
express: (app) => {
app.use(express.json({ limit: "100kb" }));
app.get("/hello", (req, res) => {
res.json({ hello: "world" });
});
app.post("/profile", (req, res) => {
res.json({ received: req.body });
});
},
// ...
});See the Express routing guide for more details.
CORS
CORS is enabled by default. You can customize the headers:
import { matchMaker } from "colyseus";
matchMaker.controller.DEFAULT_CORS_HEADERS = {
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept, Authorization',
'Access-Control-Allow-Methods': 'GET,HEAD,PUT,PATCH,POST,DELETE',
'Access-Control-Allow-Credentials': 'true',
'Access-Control-Allow-Origin': '*',
'Access-Control-Max-Age': '2592000',
// ...
}You can also return custom CORS headers based on the request:
import { matchMaker } from "colyseus";
matchMaker.controller.getCorsHeaders = function(requestHeaders) {
// check for 'requestHeaders' and return custom key-value headers here.
return {};
}See MDN documentation on CORS for more information.
Frontend Usage
Use client.http.* methods to call your HTTP endpoints from the frontend.
See Client SDK → HTTP Requests for the full API reference.