RunbooksNextAuth callback

NextAuth callback or CSRF mismatch

Applies to: core

Symptom

Signing in redirects you away from the app, or login silently fails with one of:

http://localhost:3001/api/auth/signin?error=Callback
[next-auth][error][CLIENT_FETCH_ERROR] fetch failed — Invalid URL
[next-auth][error][CSRF_TOKEN_MISMATCH]

You see the sign-in form submit, then land on a page that looks like the login screen again with no error banner.

Likely cause

NextAuthNextAuthThe auth library HiveCFM Core uses to handle sessions, OAuth providers, and credentials. reads NEXTAUTH_URL at boot and uses it to build every callback URL it hands to providers and every cookie scope. If that value disagrees with the origin the browser actually uses, the callback lands on the wrong host, the CSRF cookie is scoped to the wrong origin, or the session token is rejected.

Typical mismatches:

  • Running native dev on http://localhost:3000 but .env.local still says NEXTAUTH_URL=http://localhost:3001.
  • Running the Docker stack on http://localhost:3001 but .env still says NEXTAUTH_URL=http://localhost:3000.
  • Behind an SSH tunnel on a different host, or behind a reverse proxy that changes the origin, with NEXTAUTH_URL still pointing at localhost.

The JWTJWTA compact, signed token that carries identity between services. HiveCFM issues one per authenticated user./session callback code lives in hivecfm-core/apps/web/app/api/auth/[...nextauth]/route.ts and logs failures through @hivecfm/logger — check those logs for specifics.

Fix

Confirm the URL the browser is actually using

Open DevTools → Network and look at the first request for /api/auth/*. The origin you see there is the value NEXTAUTH_URL must match exactly — same scheme, same host, same port, no trailing slash.

Set NEXTAUTH_URL to match

Edit the env file that the server is reading:

# Docker stack (server reads hivecfm-core/.env)
NEXTAUTH_URL=http://localhost:3001
WEBAPP_URL=http://localhost:3001
# Native dev (server reads hivecfm-core/.env.local, which overrides .env)
NEXTAUTH_URL=http://localhost:3000
WEBAPP_URL=http://localhost:3000

Keep NEXTAUTH_URL and WEBAPP_URL aligned — HiveCFM builds outbound links from WEBAPP_URL.

Restart the server

NextAuth reads NEXTAUTH_URL once at startup, so an edit without a restart changes nothing:

# Docker
docker compose restart hivecfm-core
 
# Native dev
# Ctrl+C pnpm dev, then:
pnpm --filter @hivecfm/web dev

Clear the stale auth cookies

Old cookies scoped to the wrong origin will keep triggering CSRF errors. In DevTools → Application → Cookies, delete everything for the origin you are testing on (or open a private window).

Verify

  • Sign in completes and lands on the authenticated dashboard without bouncing back to /signin.
  • curl -s http://localhost:3001/api/auth/csrf returns a JSON { "csrfToken": "..." } at the same origin you intend to use.
  • No CLIENT_FETCH_ERROR or CSRF_TOKEN_MISMATCH entries in the server logs on login.

Prevent

  • Treat NEXTAUTH_URL as part of the port decision — if you change HIVECFM_PORT, update NEXTAUTH_URL and WEBAPP_URL in the same edit.
  • When tunnelling through SSH or a reverse proxy, set NEXTAUTH_URL to the external URL the browser will actually hit — not localhost.
  • Never commit a production NEXTAUTH_URL into a dev .env.local; copy from .env.example instead.