fix(auth): enable cross-site cookies for Vercel/Railway deployment#16
Conversation
The application was failing to maintain authentication state when deployed across Vercel (frontend) and Railway (backend) because cookies were blocked by strict SameSite policy.
Changes:
- Configured `SameSite=None` and `Secure=true` for auth cookies in production to allow cross-origin requests.
- Added `app.set('trust proxy', 1)` to `backend/src/server.ts` to ensure Express correctly identifies secure connections behind the reverse proxy.
- Updated `logout` route to match cookie options for successful clearing.
Co-authored-by: davidraehles <6085055+davidraehles@users.noreply.github.com>
|
👋 Jules, reporting for duty! I'm here to lend a hand with this pull request. When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down. I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job! For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with New to Jules? Learn more at jules.google/docs. For security, I will only act on instructions from the user who triggered this task. |
There was a problem hiding this comment.
Pull request overview
Enables cross-site authentication cookies so the frontend (Vercel) can maintain auth state with the backend (Railway) when they’re deployed on different sites/domains.
Changes:
- Set auth cookies to
SameSite=Nonein production (and updated logout cookie clearing options accordingly). - Configured Express to
trust proxyto better handle deployments behind a reverse proxy. - Added a
backend/pnpm-lock.yamllockfile.
Reviewed changes
Copilot reviewed 2 out of 3 changed files in this pull request and generated 4 comments.
| File | Description |
|---|---|
| backend/src/server.ts | Enables proxy trust to support secure/cookie behavior behind reverse proxies. |
| backend/src/routes/auth.ts | Updates cookie SameSite and aligns logout cookie clearing with the new cookie attributes. |
| backend/pnpm-lock.yaml | Introduces pnpm lockfile for backend dependency resolution. |
Files not reviewed (1)
- backend/pnpm-lock.yaml: Language not supported
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| res.cookie('auth_token', token, { | ||
| httpOnly: true, | ||
| secure: process.env.NODE_ENV === 'production', | ||
| sameSite: 'strict', | ||
| sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax', | ||
| maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days | ||
| path: '/', |
There was a problem hiding this comment.
SameSite=None enables the auth cookie to be sent on cross-site requests. Since authenticateToken accepts tokens from cookies, this makes any cookie-authenticated state-changing endpoints vulnerable to CSRF (e.g. the /logout POST can be triggered cross-site via a form submit). Consider adding explicit CSRF mitigation (e.g. validate Origin/Referer against ALLOWED_ORIGINS, or require a CSRF token / custom header for mutation routes when using cookie auth).
| res.cookie('auth_token', token, { | ||
| httpOnly: true, | ||
| secure: process.env.NODE_ENV === 'production', | ||
| sameSite: 'strict', | ||
| sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax', | ||
| maxAge: 7 * 24 * 60 * 60 * 1000, // 7 days | ||
| path: '/', | ||
| }); |
There was a problem hiding this comment.
Same CSRF concern as the register route: switching to SameSite=None for cookie-based auth means cross-site requests will carry the JWT cookie. If cookie auth is intended, please add CSRF protection (Origin/Referer validation, CSRF token, or require Authorization header for mutations).
| router.post('/logout', (req, res) => { | ||
| res.clearCookie('auth_token'); | ||
| res.clearCookie('auth_token', { | ||
| httpOnly: true, | ||
| secure: process.env.NODE_ENV === 'production', | ||
| sameSite: process.env.NODE_ENV === 'production' ? 'none' : 'lax', | ||
| path: '/', | ||
| }); | ||
| res.json({ message: 'Logged out successfully' }); |
There was a problem hiding this comment.
With SameSite=None, /logout becomes trivially CSRF-able because it is a state-changing POST that requires no JSON body or custom headers (so it can be triggered via a cross-site form submit). Consider adding an Origin/Referer allowlist check here (reusing ALLOWED_ORIGINS) or requiring a CSRF token/custom header before clearing the auth cookie.
| lockfileVersion: '9.0' | ||
|
|
||
| settings: | ||
| autoInstallPeers: true | ||
| excludeLinksFromLockfile: false | ||
|
|
||
| importers: | ||
|
|
||
| .: | ||
| dependencies: | ||
| '@prisma/client': | ||
| specifier: ^6.19.0 | ||
| version: 6.19.2(prisma@6.19.2(typescript@5.9.3))(typescript@5.9.3) | ||
| bcrypt: | ||
| specifier: ^6.0.0 | ||
| version: 6.0.0 | ||
| cookie-parser: | ||
| specifier: ^1.4.7 | ||
| version: 1.4.7 | ||
| cors: |
There was a problem hiding this comment.
This PR adds a pnpm-lock.yaml but backend/package-lock.json is still present. Keeping both lockfiles usually causes CI/deploy ambiguity (different tooling may pick different dependency trees). Consider removing the npm lockfile (or the pnpm lockfile), and/or adding a packageManager field in backend/package.json plus updating build instructions to clearly standardize on one package manager.
Address copilot bot review comments by implementing: - Enable SameSite=None cookies in production for cross-site auth (Vercel frontend with Railway backend) - Add CSRF validation using Origin/Referer header checking against ALLOWED_ORIGINS - Apply CSRF validation to register, login, and logout endpoints - Add trust proxy configuration to support deployments behind reverse proxies - Standardize on npm as package manager with packageManager field in package.json Addresses concerns about CSRF vulnerability when using SameSite=None cookies by implementing explicit origin validation for state-changing endpoints. https://claude.ai/code/session_01CEvBbvirScmX9qZbzt9NhV
…dress-pr-review-comments-HXXTV
…ments-HXXTV fix(auth): enable cross-site cookies and add CSRF protection
The application was failing to maintain authentication state when deployed across Vercel (frontend) and Railway (backend) because cookies were blocked by strict SameSite policy.
Changes:
SameSite=NoneandSecure=truefor auth cookies in production to allow cross-origin requests.app.set('trust proxy', 1)tobackend/src/server.tsto ensure Express correctly identifies secure connections behind the reverse proxy.logoutroute to match cookie options for successful clearing.PR created automatically by Jules for task 8949512291347004855 started by @davidraehles