Betterauth integration
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.From its SKILL.md
npx -y skills add fcsouza/agent-skills --skill betterauth-integrationAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 19 stars19 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
5.9 KB, as published. Nobody here has run it
BetterAuth Integration
Purpose
Auth flows, session management, OAuth, JWT, RBAC for game players/admins/mods using BetterAuth with Elysia + Drizzle ORM.
When to Use
Trigger: auth, authentication, login, signup, OAuth, JWT, session, RBAC, roles, permissions, player auth, admin auth, moderator, BetterAuth
Prerequisites
postgres-game-schema(for user tables)
Core Principles
"Security is not a feature. It's a foundation." — OWASP "Trust is the currency of multiplayer games." — Raph Koster
- Auth is not optional — every game endpoint must be authenticated
- Role-based access: player, moderator, admin with escalating privileges
- Session tokens over JWTs for web games — stateful > stateless for games (revocable, server-controlled)
- OAuth for social login — Discord, Google, GitHub, Twitch are standard for gamers
- Rate limit auth endpoints aggressively — prevent brute force and credential stuffing
- Never store passwords — BetterAuth handles hashing with bcrypt/argon2
- Separate game sessions from auth sessions — auth session = "who you are", game session = "what room you're in"
Step-by-Step Instructions
1. Install Dependencies
bun add better-auth drizzle-orm @neondatabase/serverless
bun add -d drizzle-kit @types/bun
2. Configure BetterAuth
Create the auth instance with Drizzle adapter, OAuth providers, and custom user fields. See boilerplate/auth-setup.ts for the complete configuration.
3. Add Auth Middleware to Elysia
Mount the BetterAuth handler and add session/role middleware to your Elysia app. See boilerplate/auth-middleware.ts for requireAuth, requireRole, and optionalAuth patterns.
4. Define Roles and Permissions
Set up the RBAC system with role enums and permission maps. See templates/role-definitions.ts for the full type definitions and permission matrix.
5. Mount Auth Routes
Add standard auth routes (signup, login, logout, OAuth, session, admin). See templates/auth-routes.ts for the route patterns.
6. Generate Auth Tables
BetterAuth manages its own tables. Run migrations after setup:
bunx drizzle-kit generate
bunx drizzle-kit migrate
7. Protect Game Endpoints
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());
Code Examples
Basic auth check in a route
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 };
});
Protecting a WebSocket connection
// 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
});
Checking role before an action
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.
Cross-References
postgres-game-schemafor user/player table schemasgame-backend-architecturefor Elysia server setup and route structureredis-game-patternsfor session caching and rate limitingstripe-game-paymentsfor authenticated payment flows
Pitfalls & Anti-Patterns
- Don't roll your own password hashing — BetterAuth handles this with battle-tested algorithms; never store plaintext or MD5
- Don't use JWTs as the sole session mechanism for web games — they can't be revoked server-side; use BetterAuth's session tokens with cookie storage
- Don't skip rate limiting on auth endpoints —
/auth/loginand/auth/signupare prime brute force targets; limit to 5-10 attempts per minute - Don't store roles in the JWT/token — always fetch the current role from the database to ensure role changes take effect immediately
- Don't use a single "admin" boolean — use a proper role enum (player/moderator/admin) so permissions can be granularly assigned
- Don't mix auth sessions with game sessions — a player can be logged in (auth session) without being in a match (game session); these are separate concerns
- Don't trust client-sent user IDs — always derive the user identity from the server-validated session, never from request body/params
- Don't forget CORS configuration — OAuth redirects and cookie-based sessions require correct origin settings
Designer Philosophy
Security 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.