JH← Back to blog

Supabase Auth and Sessions on Cloudflare Workers

Why node-assuming Supabase auth breaks on the Cloudflare Workers edge runtime, and a working pattern for JWT verification, cookies, CORS, and RLS enforcement at the edge.


Supabase's auth client was written for Node and the browser. Cloudflare Workers is neither. Moving session handling to the edge surfaces failures that aren't obvious from the docs — and the error messages don't help. Here's what breaks and the pattern that works.

Why node-assuming auth breaks on Workers

The Workers runtime doesn't have Node's globals. Libraries that reach for Buffer, Node's crypto, or process.env either throw or rely on a shim that behaves differently. Auth code is full of exactly these — JWT verification, base64 handling, secret access.

Two practical consequences:

  • Use @supabase/ssr patterns designed for server/edge contexts rather than assuming the browser client will work — cookie and storage handling differ.
  • In Next.js, marking a route as runtime = 'edge' changes what's available to it; code that ran fine in a Node route can fail once it's edge. Know which runtime each piece of your auth runs in.

The fix throughout is to lean on Web-standard APIs (Web Crypto, Request/Response, the standard fetch) instead of Node-specific ones.

Session and JWT handling at the edge

You often can't reach for jsonwebtoken on Workers. Instead, verify Supabase JWTs using the Web Crypto API directly — import the signing key and verify the token's signature with crypto.subtle. The JWT secret flows in as a Worker secret (not bundled in code).

Refresh-token mechanics need care at the edge: decide deliberately where refresh happens (typically you let the SSR layer manage the refresh/rotation and the Worker validates the access token it's handed), so you don't end up with two components both trying to rotate the same session.

Cookies, CORS, and the redirect dance

This is where cross-origin Worker deployments get fiddly. If your app origin and your Worker are on different domains, cookies need SameSite and Secure set correctly or the browser silently drops them — and "silently" is the operative word, because nothing errors; auth just doesn't stick.

Set cookies explicitly from the Worker's Response headers, get CORS right for credentialed requests (the wildcard origin won't work with credentials), and handle OAuth redirects with care when the provider returns to one domain but your session lives on another. Most "logged in but immediately logged out" bugs trace back to a cookie attribute or a CORS credential mismatch here.

RLS implications when auth runs at the edge

Row Level Security only protects you if the right identity reaches the database. Pass the user's JWT through to Supabase so RLS policies evaluate against that user — don't reach for the service-role key to "make it work," because the service role bypasses RLS entirely and turns a convenience into a security hole.

The ordering bug to watch: if the Worker makes a Supabase call before auth resolves, it either runs unauthenticated or with the wrong context. Make sure identity is established before any data access, and use the anon key + user JWT for user-scoped reads, reserving the service role for genuinely trusted server-only operations.

A working pattern

Putting it together, the shape that works:

  1. The SSR/middleware layer manages the session and hands the Worker a valid access token (via header or cookie).
  2. The Worker verifies the JWT with Web Crypto against the Supabase JWT secret.
  3. For data access, the Worker calls Supabase with the anon key plus the user's JWT, so RLS applies.
  4. Cookies are set with correct SameSite/Secure, and CORS is configured for credentialed cross-origin requests.
  5. The service-role key is used only for explicitly trusted, non-user-scoped operations — never as a shortcut around an auth bug.

FAQ

Why does Supabase auth fail on Cloudflare Workers? The Workers runtime lacks Node globals (Buffer, Node crypto, process). Use @supabase/ssr patterns and verify JWTs with the Web Crypto API.

How do I verify a Supabase JWT without jsonwebtoken? Use crypto.subtle with the JWT secret imported as a key — the Web Crypto API is available in the Workers runtime.

Why is my user logged in then immediately logged out? Almost always a cookie attribute (SameSite/Secure) or a CORS credentials mismatch on a cross-origin Worker.