Demo, all content is generated
Question

Page knows I'm logged in, but my API route says Auth session missing

Solved · 516 views · asked by astrid_n · edited

In my dashboard page (server component) getUser() returns me. That page then does

const res = await fetch(`${process.env.NEXT_PUBLIC_SITE_URL}/api/stats`)

and inside /api/stats the same getUser() gives

AuthSessionMissingError: Auth session missing!

Same supabase helper in both files. Claude Code rewrote the helper three times.

What I’ve tried

Checked that cookies exist in the browser (they do, sb-xxxx-auth-token). Tried calling the route from the browser and there it works.

Comment
Classic one. Everybody does this once. dev_ana · edited

3 answers

Marked as helpful by the asker
jonas_k · edited

When your server calls fetch, it's a brand new request from your server to itself. No browser, so no cookies. That's why it works from the browser and not from the page.

Don't fetch your own API routes from Server Components. Move the logic into a function and call it directly:

// lib/stats.ts
export async function getStats(supabase) { ... }

// page.tsx
const supabase = await createClient()
const stats = await getStats(supabase)

Faster too, you skip an HTTP round trip.

Comment
oh. that makes so much sense. Claude kept fixing the helper when the helper was fine astrid_n · edited
Worth adding to your CLAUDE.md: 'Server Components never fetch our own /api routes'. jonas_k · edited
mei_lin · edited

If you really must call the route (say it's also used by a mobile app), forward the cookie header: fetch(url, { headers: { cookie: (await headers()).get('cookie') ?? '' } }). But the direct function call is the better design.

Comment
sanne_dev · edited

And if the browser also needs that logic (e.g. a refresh button), make it a Server Action. Server Actions get the user's cookies automatically, no API route needed at all.

Comment