ec1506dc82
Wire up NextAuth v5 with @auth/pg-adapter, JWT sessions (edge-friendly), and a dev Credentials provider for local testing without Google OAuth. Stack - next-auth@5.0.0-beta.31, @auth/pg-adapter@1.11.2, @types/pg - Google OAuth provider via GOOGLE_CLIENT_ID / GOOGLE_CLIENT_SECRET (falls back to AUTH_GOOGLE_ID / AUTH_GOOGLE_SECRET) - Postgres adapter wired to a single pg.Pool in src/lib/db.ts style — reads DATABASE_URL with SUPABASE_DB_URL / POSTGRES_URL fallbacks - JWT session strategy (edge-safe) so the proxy can verify sessions without a DB round-trip Files - src/auth.config.ts edge-safe config (Google + authorized cb) - src/lib/auth.ts server config (adapter + dev Credentials) - src/proxy.ts Next.js 16 proxy (was middleware.ts) - src/app/api/auth/[...nextauth]/route.ts catch-all handler - src/app/protected-example/page.tsx demo page that renders auth() session - src/actions/auth-signin.ts signInWithGoogle, signInWithDev, signOutAction server actions - src/app/login/LoginClient.tsx added "Sign in with Google" + dev form - supabase/migrations/204_authjs_tables.sql users / accounts / sessions / verification_token schema (UUID-keyed) - .env.example AUTH_SECRET, AUTH_URL, GOOGLE_CLIENT_*, DATABASE_URL, ALLOW_DEV_LOGIN Removed - src/middleware.ts deleted; Next.js 16 only runs one proxy (the new src/proxy.ts is canonical) Routes - /login, /admin, /admin/*, /protected-example proxy matcher - /api/auth/{providers,csrf,signin/<provider>,callback/<provider>, session,signout} standard Auth.js endpoints Local dev - npm run dev (now runs on port 4000) - push migration 204 then visit /login - dev signin works with any non-empty username/password (hidden when ALLOW_DEV_LOGIN=false) - Google signin requires real GOOGLE_CLIENT_ID + redirect URI http://localhost:4000/api/auth/callback/google Verified - tsc --noEmit clean - /admin, /admin/orders, /protected-example → 307 to /login when unauthenticated - /api/auth/session returns user after signin - /protected-example renders session info - /api/auth/providers returns google + dev-login Docs - CLAUDE.md and MEMORY.md updated to reflect the Supabase → Postgres + Auth.js v5 pivot Gradual migration in progress - src/lib/admin-permissions.ts still uses dev_session / rc_auth_uid; the admin shell will show 'Access Denied' for Auth.js-only sessions until each page is flipped over - @supabase/* packages remain in package.json for the same reason - production deployment (AUTH_URL=https://, __Secure- cookies) is out of scope for this pass
74 lines
3.4 KiB
SQL
74 lines
3.4 KiB
SQL
-- ============================================================
|
|
-- Auth.js (NextAuth v5) tables
|
|
-- ============================================================
|
|
-- Schema expected by @auth/pg-adapter.
|
|
-- Reference: https://authjs.dev/getting-started/adapters/pg
|
|
--
|
|
-- Column names are kept as the adapter expects them (case-sensitive,
|
|
-- camelCase, quoted). Do NOT rename these without also updating the
|
|
-- adapter code in node_modules/@auth/pg-adapter.
|
|
--
|
|
-- We use UUIDs for user ids (consistent with the rest of the platform)
|
|
-- rather than SERIAL. The adapter doesn't care what type `id` is — it
|
|
-- just passes the value through.
|
|
-- ============================================================
|
|
|
|
-- ── users ─────────────────────────────────────────────────────
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
name TEXT,
|
|
email TEXT UNIQUE,
|
|
"emailVerified" TIMESTAMPTZ,
|
|
image TEXT,
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
|
);
|
|
|
|
-- ── accounts ─────────────────────────────────────────────────
|
|
-- One row per (provider, providerAccountId). Links external OAuth
|
|
-- accounts to a local user.
|
|
CREATE TABLE IF NOT EXISTS accounts (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
"userId" UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
type TEXT NOT NULL,
|
|
provider TEXT NOT NULL,
|
|
"providerAccountId" TEXT NOT NULL,
|
|
refresh_token TEXT,
|
|
access_token TEXT,
|
|
expires_at BIGINT,
|
|
id_token TEXT,
|
|
scope TEXT,
|
|
session_state TEXT,
|
|
token_type TEXT,
|
|
UNIQUE (provider, "providerAccountId")
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS accounts_userid_idx ON accounts ("userId");
|
|
|
|
-- ── sessions ─────────────────────────────────────────────────
|
|
-- One row per active session. With database strategy enabled, the
|
|
-- session token is stored here and looked up on every request.
|
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
"userId" UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
expires TIMESTAMPTZ NOT NULL,
|
|
"sessionToken" TEXT NOT NULL UNIQUE
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS sessions_userid_idx ON sessions ("userId");
|
|
CREATE INDEX IF NOT EXISTS sessions_expires_idx ON sessions (expires);
|
|
|
|
-- ── verification_token ──────────────────────────────────────
|
|
-- Used for email magic-link / passwordless flows. Not used by the
|
|
-- Google provider, but the adapter still references the table.
|
|
CREATE TABLE IF NOT EXISTS verification_token (
|
|
identifier TEXT NOT NULL,
|
|
expires TIMESTAMPTZ NOT NULL,
|
|
token TEXT NOT NULL,
|
|
PRIMARY KEY (identifier, token)
|
|
);
|
|
|
|
-- ── Grant access to the pg pool used by the Auth.js adapter ──
|
|
-- (No-op if you're connecting as the table owner; included for
|
|
-- completeness in case a separate app role is used.)
|
|
-- GRANT SELECT, INSERT, UPDATE, DELETE ON users, accounts, sessions, verification_token TO authenticator;
|