Add session-based authentication with login/logout
- Users and sessions tables (Argon2 password hashing, SHA-256 session tokens) - Server hooks validate session cookie on every request - (app) routes redirect to /login if not authenticated - Login page with email/password, styled matching budget app - Logout via POST form action (invalidates session) - User display name and sign out button in header - create-user CLI script: npm run create-user <email> <password> [name] - 30-day sessions with auto-refresh after 15 days Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,25 @@ import {
|
||||
} from 'drizzle-orm/pg-core';
|
||||
import { sql } from 'drizzle-orm';
|
||||
|
||||
// ─── Users & Sessions ──────────────────────────────────────────────
|
||||
|
||||
export const users = pgTable('users', {
|
||||
id: text('id').primaryKey(),
|
||||
email: text('email').unique().notNull(),
|
||||
displayName: text('display_name'),
|
||||
passwordHash: text('password_hash').notNull(),
|
||||
createdAt: timestamp('created_at', { withTimezone: true }).defaultNow().notNull(),
|
||||
updatedAt: timestamp('updated_at', { withTimezone: true }).defaultNow().notNull()
|
||||
});
|
||||
|
||||
export const sessions = pgTable('sessions', {
|
||||
id: text('id').primaryKey(), // SHA-256 hash of the session token
|
||||
userId: text('user_id')
|
||||
.notNull()
|
||||
.references(() => users.id, { onDelete: 'cascade' }),
|
||||
expiresAt: timestamp('expires_at', { withTimezone: true }).notNull()
|
||||
});
|
||||
|
||||
// ─── Locations ──────────────────────────────────────────────────────
|
||||
|
||||
export const locations = pgTable('locations', {
|
||||
|
||||
Reference in New Issue
Block a user