Mobile/LAN Testing

Mobile/LAN Login Troubleshooting

Use this only for local dashboard testing on a trusted LAN. It does not change production auth settings.

Use this when...

Use this when something is not behaving as expected.

Use this only for local dashboard testing on a trusted LAN. It does not change production auth settings.

Start the dashboard for LAN

Run:

pnpm dev:lan

This serves the web app on 0.0.0.0:3000, which allows another device on the same network to reach the dashboard.

pnpm dev:lan starts the dashboard/web app only. To review the documentation app at http://localhost:3001 at the same time, run this separately in another terminal:

pnpm dev:docs

Find the Windows IPv4 address

Run:

ipconfig

Find the active Wi-Fi or Ethernet adapter and copy the IPv4 Address, for example 192.168.1.23.

Open from a phone

Connect the phone to the same Wi-Fi network, then open:

http://<PC-IP>:3000

Example:

http://192.168.1.23:3000

Auth environment

For normal desktop development keep:

BETTER_AUTH_URL=http://localhost:3000

In local development, Better Auth resolves the current request host and accepts these port 3000 origins:

  • http://localhost:3000
  • http://127.0.0.1:3000
  • private LAN IPs such as http://192.168.18.22:3000, http://10.x.x.x:3000, and http://172.16.x.x through http://172.31.x.x

If a local hostname outside those patterns is needed, add only that development host to the untracked .env:

BETTER_AUTH_DEV_ALLOWED_HOSTS=my-dev-host.local:3000

Restart pnpm dev:lan after changing .env. Do not use a LAN URL for production, do not commit .env, and do not weaken production secure-cookie or trusted-origin behavior.

Sprint 16B LAN sign-out fix record

Root cause:

  • LAN sign-out depended on hydrated client-side auth code.
  • On local LAN dev origins, Next.js dev resources can be blocked or delayed, so the page can load while the client sign-out handler does not reliably clear the active session.
  • Sign-out must clear the cookie for the current request host and redirect relative to that same host, not hardcode localhost.

Files changed for the fix:

  • apps/web/src/components/logout-button.tsx
  • apps/web/src/app/logout/submit/route.ts
  • apps/web/src/app/login/page.tsx
  • apps/web/next.config.ts
  • apps/docs/content/mobile-lan-testing.md

Auth/session/cookie/redirect behavior:

  • The sign-out button now submits a regular POST form to /logout/submit.
  • The server route calls Better Auth sign-out when available.
  • If the auth client path is unavailable in local LAN dev, the route deletes the active database session from the current submicron.session_token cookie.
  • The route expires host-only submicron.session_token cookies and redirects to /login on the same request host.
  • Production secure-cookie behavior remains unchanged.

Retest result to record after local verification:

  • http://localhost:3000/login login and sign-out work.
  • http://192.168.18.22:3000/login login and sign-out work on the computer.
  • http://192.168.18.22:3000/login login and sign-out work on the phone.

Remaining limitation:

  • LAN testing still requires the phone and PC to be on the same trusted local network, and a dev server running with pnpm dev:lan.

Sprint 15 LAN login fix record

Root cause:

  • Better Auth originally trusted only the configured BETTER_AUTH_URL, so local LAN origins such as http://192.168.18.22:3000 could fail origin/callback validation even though the page loaded.
  • The login form was client-handled only. During local LAN/loopback testing, if the client submit handler was not active yet, the browser could fall back to native form submission and return to the login page without a useful visible error.
  • When the app is served on 0.0.0.0, server-side redirects must be rebuilt from the incoming Host header so they return to localhost, 127.0.0.1, or the LAN IP instead of 0.0.0.0.

Files changed for the fix:

  • apps/web/src/lib/auth.ts
  • apps/web/src/lib/auth-diagnostics.ts
  • apps/web/src/app/api/auth/[...all]/route.ts
  • apps/web/src/app/api/dev/auth-diagnostics/route.ts
  • apps/web/src/app/login/page.tsx
  • apps/web/src/app/login/submit/route.ts
  • apps/web/src/components/login-form.tsx
  • apps/web/src/proxy.ts
  • .env.example
  • apps/docs/content/mobile-lan-testing.md
  • apps/docs/content/local-development.md

Auth, session, cookie, and redirect changes:

  • Local development auth resolves the current request host for localhost:3000, 127.0.0.1:3000, and private LAN IPs on port 3000.
  • Production auth remains static and secure; secure-cookie behavior is not weakened for production.
  • Development cookies remain host-only, sameSite=lax, path /, and non-secure only for local HTTP development.
  • The login form posts to /login/submit as a progressive-enhancement fallback while the hydrated client still uses Better Auth directly.
  • /login/submit forwards the form credentials to Better Auth, copies the session cookie on success, and redirects back to the same incoming host.
  • Failed login returns to /login?error=invalid&email=...; the email is preserved and the password is never placed in the URL.
  • Development-only diagnostics are available at /api/dev/auth-diagnostics; production returns 404 and no secrets are exposed.

Retest result:

  • http://localhost:3000/login: verified on the computer. Successful login sets a session cookie, redirects to /, and loads the dashboard.
  • http://127.0.0.1:3000/login: verified on the computer. Successful login sets a session cookie, redirects to /, and loads the dashboard.
  • http://192.168.18.22:3000/login: verified on the computer. Successful login sets a session cookie, redirects to /, and loads the dashboard.
  • http://192.168.18.22:3000/login on a phone: fixed and verified by user confirmation on the same Wi-Fi network. The phone login reaches the dashboard using the LAN IP host, host-only development cookie, and same-origin redirect path.

Remaining limitations:

  • If the phone login regresses later, clear cookies/site data for the LAN IP, restart pnpm dev:lan, and confirm the phone is on the same Wi-Fi network.
  • Root pnpm lint and pnpm test currently run the repository typecheck pipeline. Use pnpm typecheck when you want the same verification path explicitly.

Troubleshooting

  • If login fails on the computer when using http://<PC-IP>:3000/login, restart pnpm dev:lan, confirm the route is on the current branch, then try http://localhost:3000/login, http://127.0.0.1:3000/login, and http://<PC-IP>:3000/login.
  • Open http://<PC-IP>:3000/api/dev/auth-diagnostics during local development to confirm the request host, host classification, database availability, session-cookie presence, and cookie settings. This route returns 404 in production and does not expose secrets.
  • If the login form reports a local auth URL error, confirm the browser URL uses port 3000 and a localhost, loopback, or private LAN host.
  • If the form reports that the session could not be created, confirm Docker/PostgreSQL is running and rerun pnpm db:seed if the admin account may be missing.
  • If the page loads but login still loops back, clear cookies for the LAN IP and retry after restarting pnpm dev:lan.
  • If the phone cannot load the page, confirm the phone and PC are on the same network and Windows Firewall allows local Node.js traffic.
  • If a newly added route returns 404 during local dev, restart pnpm dev or pnpm dev:lan and confirm the current Git branch contains the route.
Developer Details
Source
apps/docs/content/mobile-lan-testing.md
Owner
Module Owner
Status
Current
Module
Mobile/LAN Testing
Related route
None