ServerHTTP Routes

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.

app.config.ts
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:

app.config.ts
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

OptionDescription
usersRecord<string, string> mapping username → password. The common static case.
validate(username, password) => boolean | Promise<boolean>: custom/DB-backed check. Takes precedence over users.
realmLabel 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:

OptionDescription
methodHTTP method string or array (e.g. "GET" or ["GET", "POST"]).
bodyZod schema for request body validation. Invalid bodies return 400.
queryZod schema for query string validation. Invalid queries return 400.
useArray of middlewares created with createMiddleware.
requireHeadersWhen true, requires headers when calling the endpoint as a function.
requireRequestWhen 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.allowedMediaTypesRestricts accepted Content-Type values for this endpoint.

Handler Context

The handler signature is async (ctx) => response.

Properties

PropertyDescription
ctx.requestThe raw Request object (when running via HTTP).
ctx.headersHeaders instance for the incoming request.
ctx.bodyParsed and validated request body.
ctx.queryParsed and validated query string.
ctx.paramsRoute parameters (e.g. :id, **:name).
ctx.methodHTTP method (useful for multi-method endpoints).
ctx.contextMerged middleware context.

Methods

MethodDescription
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.

app.config.ts
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.