skills/betterauth-integration/SKILL.md
Use when implementing authentication, login flows, OAuth, JWT sessions, or role-based access control (RBAC) for games with BetterAuth. Triggers: auth, login, OAuth, JWT, roles, permissions, RBAC.
npx skillsauth add fcsouza/agent-skills engineering-betterauth-integrationInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Auth flows, session management, OAuth, JWT, RBAC for game players/admins/mods using BetterAuth with Elysia + Drizzle ORM.
Trigger: auth, authentication, login, signup, OAuth, JWT, session, RBAC, roles, permissions, player auth, admin auth, moderator, BetterAuth
postgres-game-schema (for user tables)"Security is not a feature. It's a foundation." — OWASP "Trust is the currency of multiplayer games." — Raph Koster
bun add better-auth drizzle-orm @neondatabase/serverless
bun add -d drizzle-kit @types/bun
Create the auth instance with Drizzle adapter, OAuth providers, and custom user fields. See boilerplate/auth-setup.ts for the complete configuration.
Mount the BetterAuth handler and add session/role middleware to your Elysia app. See boilerplate/auth-middleware.ts for requireAuth, requireRole, and optionalAuth patterns.
Set up the RBAC system with role enums and permission maps. See templates/role-definitions.ts for the full type definitions and permission matrix.
Add standard auth routes (signup, login, logout, OAuth, session, admin). See templates/auth-routes.ts for the route patterns.
BetterAuth manages its own tables. Run migrations after setup:
bunx drizzle-kit generate
bunx drizzle-kit migrate
Apply middleware to all game routes:
import { requireAuth, requireRole } from './auth-middleware';
app
.use(requireAuth)
.get('/api/game/state', ({ user }) => getGameState(user.id))
.use(requireRole('admin'))
.delete('/api/game/reset', () => resetGame());
import { auth } from './auth-setup';
app.get('/api/me', async ({ headers }) => {
const session = await auth.api.getSession({ headers });
if (!session) return { error: 'Not authenticated' };
return { user: session.user };
});
// Validate session before upgrading to WebSocket
app.ws('/ws', {
async beforeHandle({ headers }) {
const session = await auth.api.getSession({ headers });
if (!session) throw new Error('Unauthorized');
},
// ... ws handlers
});
import { hasPermission } from './role-definitions';
app.delete('/api/players/:id/ban', async ({ user, params }) => {
if (!hasPermission(user.role, 'users', 'ban')) {
return { error: 'Insufficient permissions' };
}
await banPlayer(params.id, user.id);
return { banned: true };
});
See boilerplate/auth-setup.ts and boilerplate/auth-middleware.ts for full implementation patterns.
postgres-game-schema for user/player table schemasgame-backend-architecture for Elysia server setup and route structureredis-game-patterns for session caching and rate limitingstripe-game-payments for authenticated payment flows/auth/login and /auth/signup are prime brute force targets; limit to 5-10 attempts per minuteSecurity enables trust; trust enables social gameplay. When players know their accounts are safe, they invest more in the game — socially, economically, and emotionally. Authentication is invisible when done right: players log in once, stay logged in, and never think about it again. Every friction point in auth is a player lost.
tools
Use when implementing client-server state synchronization, delta compression, optimistic updates, rollback netcode, or real-time game state reconciliation. Triggers: state sync, netcode, delta, rollback, interpolation, prediction.
testing
Use when designing virtual economies, currencies, sink/faucet balance, loot tables, crafting systems, shops, or inflation control. Triggers: economy, currency, sinks, loot, inflation, crafting, shop.
development
Audits existing game code against design principles — checks server-authority, schema conventions, auth security, payment safety, narrative coherence, and MVP scope drift. Extract the optional component name or path from the user's message (defaults to entire src/). Use after building components or before committing.
testing
Designs a single quest end-to-end — coherence check, objective tree, quest brief, and registry entry. Extract the quest name from the user's message. Requires docs/world-lore.md and docs/quest-registry.md.