CRUMB a card from devarno-cloud

BetterAuth Session Cookie & Edge Middleware

so1 intermediate 4 min read

ELI5

The middleware is a bouncer at the door of every protected page: it peeks for the so1.session_token wristband. No wristband, you go to /auth/login. Already wristbanded but trying to re-enter the line, you get nudged to /dashboard.

Technical Deep Dive

src/middleware.ts chooses the cookie based on NODE_ENV:

EnvCookie Name
developmentso1.session_token
production__Secure-so1.session_token

The __Secure- prefix is enforced when useSecureCookies: true in BetterAuth — it requires HTTPS and rejects plaintext setting.

Decision Flow

flowchart TD
start[request] --> match{matcher hit?}
match -- no, asset/_next --> pass[pass through]
match -- yes --> read[read SESSION_COOKIE]
read --> auth{authenticated?}
auth -- no --> prot{protected prefix?}
prot -- no --> pass2[pass through]
prot -- yes --> login["redirect /auth/login?callbackUrl=…"]
auth -- yes --> isauth{is /auth/login or /auth/signup?}
isauth -- yes --> dash[redirect /dashboard]
isauth -- no --> pass3[pass through]

Protected Prefixes

Hard-coded in PROTECTED_PREFIXES: /dashboard, /content, /catalog, /workflows, /jobs, /agents, /pathfinder, /elevator, /branding, /social, /subsystems, /settings.

Matcher

The config.matcher excludes Next.js internals (_next) and common static assets (html, css, images, fonts, csv/xlsx/zip, webmanifest), and explicitly opts in (api|trpc)(.*).

Implementation Note

ADR-001 specifies Clerk OIDC; the codebase has since migrated to BetterAuth. The cookie-based check above is the live implementation in src/middleware.ts.

Key Terms

  • Edge runtime → Next.js middleware runs in V8 isolates close to the user, not Node.
  • __Secure- prefix → browser-enforced rule that the cookie must have Secure and was set over HTTPS.
  • callbackUrl → query param the login page reads to bounce the user back after success.

Q&A

Q: Does the middleware actually validate the session token’s signature? A: No — it only checks for the cookie’s presence. Signature/expiry validation is the BFF’s job, so a stale cookie still reaches a protected page and gets a 401 from data-fetching hooks.

Q: A request to /api/bff/jobs without a cookie — what happens? A: The matcher includes /api, but since /api is not in PROTECTED_PREFIXES the request passes through; the BFF then rejects with 401.

Q: How do I add a new authed section? A: Append the prefix to PROTECTED_PREFIXES in src/middleware.ts.

Examples

Visiting /jobs while logged out redirects to /auth/login?callbackUrl=%2Fjobs. After successful sign-in, BetterAuth sets the cookie; the next navigation to /jobs passes the bouncer.

neighbors on the map