Authentication
How OTP, Magic Link, and session-based auth work across the RocketX platform.
Centralized Auth Architecture
All authentication logic lives in the Express backend. Next.js is a pure consumer — no auth logic runs in Next.js middleware or server actions.
- OTP + Magic Link: Both are dispatched simultaneously to the user's email via Resend (or Nodemailer SMTP fallback).
- Password reset: Time-limited token flow via email.
- Session cookie: On successful login the API sets a secure, HttpOnly
better-auth.session_tokencookie.
The Proxy Rewrite
next.config.ts rewrites /api/* to the Express server so the browser always talks to one origin and cookies are scoped correctly:
// apps/web/next.config.ts
async rewrites() {
return [
{ source: "/api/:path*", destination: "https://api.rocketx.market/:path*" },
];
}
Session Verification
The requireAuth Express middleware reads the auth-token JWT cookie (signed with ENCRYPTION_KEY) and attaches req.user to every authenticated request. The Next.js AuthGuard fetches /api/v1/auth/session to hydrate the Zustand auth store on the client.
GitHub OAuth (Developer Feature)
Connecting GitHub to the Developer Portal uses a stateful OAuth flow:
GET /v1/developer/github/connect— signs a short-lived HS256 state JWT containing{ userId, purpose: "github-connect", returnTo }and redirects to GitHub App installation.- GitHub redirects back to
GET /v1/developer/github/callback— this route is public (registered beforerequireAuth). It verifies the state JWT, exchanges the installation ID, saves it to the user's record, then redirects toreturnTo.
Cookie Domain Strategy
Because auth uses HttpOnly cookies, UI and API must share a cookie domain:
| Environment | Cookie domain |
|---|---|
| Local dev | localhost (browser handles automatically) |
| Production | .yourdomain.com (set AUTH_DOMAIN=.yourdomain.com in API env) |
In production, both
app.yourdomain.comandapi.yourdomain.commust sit under.yourdomain.com.