NEXT_PUBLIC_GARY_SKIP_AUTH build-time flag bypasses Supabase login

A single commit adds a frontend-only Supabase auth bypass gated on `NEXT_PUBLIC_GARY_SKIP_AUTH=true`. When set, `AuthContext` skips the auth flow and seeds a fake demo user. An amber banner renders in the protected layout. Backend calls still 401 - the bypass is for UI inspection only.

securityworkflow

The mechanism uses lazy useState initializers so no setState runs inside the auth effect. SKIP_AUTH is resolved once at module load time from process.env.NEXT_PUBLIC_GARY_SKIP_AUTH; when true, the initial user state is { id: "00000000-0000-0000-0000-000000000000", email: "demo@gary.local" } and authLoading starts as false. The Supabase subscription and ensure-profile POST are skipped. signOut is a no-op because the "session" is synthetic.

The context exposes isAuthBypassed: boolean. The protected layout ((pages)/layout.tsx) reads it and conditionally renders a DevAuthBanner component - a 21-line amber strip with role="status" - at the top of the page. The variable is commented out in .env.local.example so default installs see real auth.

The catch is worth spelling out clearly. NEXT_PUBLIC_* is baked into the client bundle at build time on Cloudflare Workers via OpenNext. This isn't a runtime toggle - enabling it requires a rebuild. That makes accidental production exposure less likely than a runtime env var, but the only guard is a string comparison against the env value. There's no NODE_ENV !== "production" check. A production build with NEXT_PUBLIC_GARY_SKIP_AUTH=true in the environment would ship a publicly accessible frontend with no login required.

So what The fake-user shim and `isAuthBypassed` context flag are useful patterns for a dev/demo Worker. Before importing, add a `process.env.NODE_ENV !== "production"` guard to the `SKIP_AUTH` constant so a misconfigured production build can't accidentally bypass auth. The `DevAuthBanner` is a good inclusion regardless.

View this fork on GitHub →

Spotted something wrong? Or know the PR text has fresher detail than the writeup above?

Commits in this thread

2 commits from foolish-bandit/gary, oldest first. Source extracted verbatim from the harvested git log.

SHA Subject Author Date
ad478709 Merge pull request #11 from foolish-bandit/claude/dev-auth-bypass Zack Brenner 2026-05-07 ↗ GitHub
Add NEXT_PUBLIC_GARY_SKIP_AUTH dev/demo bypass
0b9ad4db Add NEXT_PUBLIC_GARY_SKIP_AUTH dev/demo bypass Claude 2026-05-07 ↗ GitHub
commit body
Lets us inspect the app without going through Supabase login during
development and on demo deploys. Frontend-only.

When NEXT_PUBLIC_GARY_SKIP_AUTH=true:
- AuthContext initializes with a fake demo user
  ({ id: "00000000-...-000", email: "demo@gary.local" }) via lazy
  useState, so isAuthenticated is true immediately.
- The Supabase session check + auth-state-change subscription are
  skipped (the useEffect bails out after a one-time console.warn).
- signOut becomes a no-op so the demo session stays stable.
- A slim amber "Dev auth bypass enabled" banner renders at the top
  of the (pages) layout via the new DevAuthBanner component.
- The flag is exposed as `isAuthBypassed` on the auth context so
  any consumer can branch on it later.

When the flag is unset or "false":
- useState initializers return null/true, identical to today.
- The effect's bypass branch is dead and the original Supabase
  logic runs unchanged. Login/signup, signOut, and the redirect
  gate in (pages)/layout.tsx are untouched.

Documents the variable in frontend/.env.local.example as
commented-out so normal setups stay on real auth.

No backend changes, no schema changes, no auth contract changes.
Backend calls made while the bypass is on will 401 because no
real Supabase session exists - that's intentional and noted in
the console warning.

https://claude.ai/code/session_019pRkhcGDRKQWHjzAnV5yCL

Capture this thread into my fork

Download a single Markdown prompt that tells Claude how to port every commit above into your working tree — adapting paths and structure to match your repo. Run it via claude -p < capture-thread-164.md from inside the repo you want the changes in.

⬇ Download capture-thread-164.md