React+Node.js认证系统部署后Refresh Token无响应问题排查
Hey there! Let's dive into why your refresh token works locally but breaks in production—this is a super common scenario when deploying to Vercel and Heroku, so let's walk through the most likely causes:
1. Misconfigured CORS Settings
Local development often uses a proxy (like React's package.json proxy field) to bypass CORS restrictions, but in production, your Vercel frontend and Heroku backend are separate origins.
- Double-check your Node.js backend's CORS configuration: make sure it explicitly allows your Vercel domain (
https://jwt-auth-client.vercel.app) as an allowed origin, and enablescredentials: true(critical for sending cookies with refresh tokens). - Example CORS setup using the
corsnpm package:const corsOptions = { origin: process.env.NODE_ENV === 'production' ? 'https://jwt-auth-client.vercel.app' : 'http://localhost:3000', credentials: true }; app.use(cors(corsOptions));
2. Incorrect Cookie Security Attributes
Browsers enforce stricter cookie rules in HTTPS production environments compared to local HTTP:
SecureAttribute: Must be set totruein production—browsers won't store cookies marked as non-secure over HTTPS.SameSiteAttribute: Since your frontend (vercel.app) and backend (herokuapp.com) are cross-domain, setSameSite: "None"(paired withSecure: true) to ensure the cookie is sent across origins.HttpOnly: Keep this enabled to prevent XSS attacks, but ensure it's not conflicting with other settings.- Example cookie setup:
res.cookie('refreshToken', refreshToken, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: process.env.NODE_ENV === 'production' ? 'None' : 'Lax', maxAge: 7 * 24 * 60 * 60 * 1000 // 7 days });
3. Heroku Dyno Persistence Issues
Heroku dynos are ephemeral—any in-memory storage (like storing refresh tokens in a local array) will be wiped when the dyno restarts.
- Ensure your refresh tokens are persisted to a database (MongoDB, PostgreSQL, etc.) instead of stored in memory. If you're using a cache like Redis, make sure it's properly configured as an add-on in Heroku, not relying on local Redis.
4. Mismatched Environment Variables
It's easy to overlook production environment variables:
- Verify that Heroku's environment variables (like
JWT_SECRET, database connection strings) match exactly what you're using locally. A mismatchedJWT_SECRETwill cause refresh token validation to fail silently. - Check Heroku's dashboard under "Settings" > "Config Vars" to confirm all required variables are set correctly.
5. Vercel Frontend Caching
Vercel aggressively caches static assets, which can lead to outdated frontend code running in production:
- If you updated your refresh token request logic (like adding
credentials: 'include'to fetch calls), old cached versions might still be running. Try clearing Vercel's cache via the dashboard, or add content hashing to your build outputs to bust cache automatically.
6. Mixed Content Errors
If your frontend accidentally makes HTTP requests to your HTTPS Heroku backend, browsers will block these "mixed content" requests:
- Ensure all API calls in your React app use the HTTPS URL of your Heroku backend (e.g.,
https://your-backend-app.herokuapp.com/api/refresh), not HTTP.
Quick Debugging Steps
- Open your browser's DevTools > Network tab, trigger the refresh token request, and check:
- Does the request include the
refreshTokencookie in the "Request Headers"? - What's the response status code? (401 = invalid token, 500 = server error, 403 = CORS issue)
- Does the request include the
- Check Heroku logs in real-time with
heroku logs --tailto see server-side errors (like JWT validation failures or database connection issues).
内容的提问来源于stack exchange,提问作者סרגיי לוייב

