Authentication
When @colyseus/auth is installed alongside @colyseus/database and you pass database: to defineServer, the database becomes the user store and all auth routes mount automatically. The only callbacks left to write are the email-delivery ones.
What’s wired automatically:
- HTTP routes: every endpoint from
@colyseus/auth(register, login, forgot/reset password, OAuth callback) is spread into your router under the configured prefix. - User store:
db.auth.settingssupplies the user-store Backend API callbacks (onFindUserByEmail,onRegisterWithEmailAndPassword,onRegisterAnonymously,onResetPassword,onOAuthProviderCallback,onCheckBanned). Email delivery is not included: wireonForgotPassword(andonSendEmailConfirmation/onEmailConfirmedif you use email verification) yourself, or those flows silently no-op. - Ban gating at login:
onCheckBannedrejects banned users and surfaces{ reason, until }from the row. - JWT session revocation: JWTs carry a
tokenVersionclaim.db.auth.ban()atomically bumps the version alongside the ban fields, so any previously-issued JWT for that user is rejected on its next room join. HTTP routes verify only signature and expiry (see HTTP API Auth).db.auth.bumpTokenVersion(userId)is also available standalone for password changes, “sign out everywhere”, and forced rotation. - Password-hash handoff:
@colyseus/authhashes passwords before they reach the database; the DB never sees plaintext.
The same env secrets (JWT_SECRET, SESSION_SECRET) still apply. See Auth Module → Required Environment Secrets.
Minimal setup
Once database: is set on defineServer, the auth integration is live. No additional wiring is required:
import { defineServer } from "colyseus";
import { GameDatabase } from "@colyseus/database";
export const db = new GameDatabase({ connectionString: process.env.DATABASE_URL });
export default defineServer({
database: db, // ← wires @colyseus/auth routes + user store automatically
});Admin & moderation helpers
db.auth exposes account-management methods called from admin tooling or moderation flows:
await db.auth.ban(userId, { reason: "cheating", until: new Date(Date.now() + 86_400_000) });
const status = await db.auth.isBanned(userId); // { banned, reason?, until? }
await db.auth.unban(userId);
// Force-log-out: previously issued JWTs are rejected on the next room join
await db.auth.bumpTokenVersion(userId);Customizing callbacks
To wrap or replace individual callbacks, override keys on the auth.settings singleton after the server boots. For example, add an invite-code check during registration, or customize the anonymous user payload. The database wiring copies db.auth.settings into auth.settings at listen time, so any override applied earlier is overwritten:
import { auth } from "@colyseus/auth";
await server.listen(2567);
// after listen(): wrap the database-provided callback
const original = auth.settings.onRegisterWithEmailAndPassword;
auth.settings.onRegisterWithEmailAndPassword = async (email, password, options) => {
if (options.inviteCode !== process.env.INVITE_CODE) {
throw new Error("invalid invite code");
}
return original(email, password, options);
};See the Backend API catalog for the full list of hooks. Assign onto auth.settings, not db.auth.settings, whose getter returns a fresh throwaway object on every access.
Not using @colyseus/database? See Auth Module for the manual setup: implement the Backend API callbacks against your own database.