1e9f9c0414
Deploy to route.crispygoat.com / deploy (push) Failing after 2s
After a user signs in with Google, they land on /admin but see
'Your account does not have admin access' because getAdminUser()
only checked the legacy dev_session and rc_auth_uid cookies.
This completes the Auth.js path:
- New src/lib/db.ts: shared pg.Pool singleton (extracted from
src/lib/auth.ts). The single connection pool for the whole app
— server actions, API routes, and Auth.js all import from here.
- src/lib/auth.ts: imports the shared pool, signIn event now calls
the new upsert_admin_user_for_authjs RPC (idempotent) to
auto-create a platform_admin row on first sign-in.
- New supabase/migrations/209_authjs_auto_create_admin.sql:
- Defensive ALTER TABLE ADD COLUMN IF NOT EXISTS for
can_manage_settings (was likely dashboard-added, not in any
tracked migration)
- SECURITY DEFINER RPC upsert_admin_user_for_authjs(p_user_id UUID)
that inserts a platform_admin row with all permissions true
and ON CONFLICT (user_id) DO NOTHING
- NOTIFY pgrst to reload PostgREST schema cache
- src/lib/admin-permissions.ts: new Auth.js session check between
dev_session and rc_auth_uid. Uses auth() from @/lib/auth to
decrypt the JWT cookie server-side, then getAdminUserFromPool()
queries admin_users + admin_user_brands via the shared pool.
Legacy rc_auth_uid path unchanged (deferred).
- src/middleware.ts: recognizes Auth.js session cookies
(authjs.session-token and __Secure-authjs.session-token) at the
edge so signed-in users aren't bounced to /login.
Flow after this change:
Dev/demo: visit /admin → middleware auto-issues dev_session → in
Prod: click Google → Auth.js OAuth → signIn event creates
admin_users row → redirect to /admin → getAdminUser()
reads JWT, queries pool, returns platform_admin.
67 lines
1.7 KiB
PL/PgSQL
67 lines
1.7 KiB
PL/PgSQL
-- 209_authjs_auto_create_admin.sql
|
|
-- Auto-create a platform_admin row when a new user signs in via Auth.js.
|
|
--
|
|
-- Called from the `signIn` event in `src/lib/auth.ts`. The RPC is
|
|
-- idempotent (ON CONFLICT DO NOTHING) so repeat sign-ins are no-ops.
|
|
|
|
-- Defensive: ensure can_manage_settings column exists. It was likely
|
|
-- added via the Supabase dashboard (it's referenced in the TypeScript
|
|
-- `AdminUser` type at `src/lib/admin-permissions-types.ts` but not in
|
|
-- any tracked migration). ADD COLUMN IF NOT EXISTS is safe to re-run.
|
|
ALTER TABLE admin_users
|
|
ADD COLUMN IF NOT EXISTS can_manage_settings BOOLEAN NOT NULL DEFAULT false;
|
|
|
|
-- SECURITY DEFINER RPC: upsert a platform_admin row for the given
|
|
-- Auth.js user id.
|
|
--
|
|
-- Bypasses RLS on admin_users (which is enabled — see
|
|
-- 109_enable_rls_critical.sql:21). Runs with the function owner's
|
|
-- privileges so the auto-create on first sign-in can always succeed.
|
|
CREATE OR REPLACE FUNCTION upsert_admin_user_for_authjs(p_user_id UUID)
|
|
RETURNS SETOF admin_users
|
|
LANGUAGE plpgsql
|
|
SECURITY DEFINER
|
|
SET search_path = public
|
|
AS $$
|
|
BEGIN
|
|
RETURN QUERY
|
|
INSERT INTO admin_users (
|
|
user_id,
|
|
role,
|
|
active,
|
|
must_change_password,
|
|
can_manage_products,
|
|
can_manage_stops,
|
|
can_manage_orders,
|
|
can_manage_pickup,
|
|
can_manage_messages,
|
|
can_manage_refunds,
|
|
can_manage_users,
|
|
can_manage_water_log,
|
|
can_manage_reports,
|
|
can_manage_settings
|
|
)
|
|
VALUES (
|
|
p_user_id,
|
|
'platform_admin',
|
|
true,
|
|
false,
|
|
true,
|
|
true,
|
|
true,
|
|
true,
|
|
true,
|
|
true,
|
|
true,
|
|
true,
|
|
true,
|
|
true
|
|
)
|
|
ON CONFLICT (user_id) DO NOTHING
|
|
RETURNING *;
|
|
END;
|
|
$$;
|
|
|
|
-- Reload PostgREST schema cache so the new RPC is immediately callable.
|
|
NOTIFY pgrst, 'reload schema';
|