Session Authentication
Session-based auth stores state on the server and identifies requests via a signed cookie. Velox TS sessions include HMAC-SHA256 signing, sliding expiration, flash messages, and session regeneration on login to prevent fixation attacks.
import { sessionMiddleware, inMemorySessionStore } from '@veloxts/auth';
const session = sessionMiddleware({ secret: process.env.SESSION_SECRET!, store: inMemorySessionStore(), // Use Redis in production cookie: { name: 'session', secure: true, httpOnly: true, sameSite: 'lax', maxAge: 86400, // 24 hours },});Login Flow
Section titled “Login Flow”login: procedure() .use(session.optional()) .input(LoginSchema) .mutation(async ({ input, ctx }) => { const user = await verifyCredentials(input);
// Create session (regenerates session ID to prevent fixation) await ctx.session.login({ id: user.id, email: user.email, });
return { user }; }),Logout
Section titled “Logout”logout: procedure() .use(session.required()) .mutation(async ({ ctx }) => { await ctx.session.logout(); return { success: true }; }),Protecting Routes
Section titled “Protecting Routes”getProfile: procedure() .use(session.required()) .query(({ ctx }) => ctx.user),
// Optional auth (user may or may not be logged in)homePage: procedure() .use(session.optional()) .query(({ ctx }) => ({ user: ctx.user ?? null })),Flash Messages
Section titled “Flash Messages”// Set flash messagectx.session.flash('success', 'Profile updated!');
// Read flash message (one-time)const message = ctx.session.getFlash('success');Production: Custom Store
Section titled “Production: Custom Store”For production, implement the SessionStore interface with Redis or another persistent store:
import type { SessionStore, StoredSession } from '@veloxts/auth';import Redis from 'ioredis';
function createRedisStore(redis: Redis): SessionStore { return { async get(id: string): Promise<StoredSession | null> { const data = await redis.get(`session:${id}`); return data ? JSON.parse(data) : null; }, async set(id: string, session: StoredSession, ttl: number): Promise<void> { await redis.setex(`session:${id}`, ttl, JSON.stringify(session)); }, async destroy(id: string): Promise<void> { await redis.del(`session:${id}`); }, async touch(id: string, ttl: number): Promise<void> { await redis.expire(`session:${id}`, ttl); }, };}
const session = sessionMiddleware({ store: createRedisStore(new Redis(process.env.REDIS_URL)), // ...});