Tengo una aplicación React que hace llamadas a una API en node.js/Express.
Frontend se implementa en Netlify (https), Backend se implementa en Heroku (https).
Mi problema:
Hablar es barato, muéstrame el código....
Aplicación.js
require('./configs/passport'); // ... const app = express(); // trust proxy (https://stackoverflow.com/questions/64958647/express-not-sending-cross-domain-cookies) app.set("trust proxy", 1); app.use( session({ secret: process.env.SESSION_SECRET, cookie: { sameSite: process.env.NODE_ENV === "production" ? 'none' : 'lax', maxAge: 60000000, secure: process.env.NODE_ENV === "production", }, resave: true, saveUninitialized: false, ttl: 60 * 60 * 24 * 30 }) ); app.use(passport.initialize()); app.use(passport.session()); // ... app.use( cors({ credentials: true, origin: [process.env.FRONTEND_APP_URL] }) ); //... app.use('/api', require('./routes/auth-routes')); app.use('/api', require('./routes/item-routes'));Punto final CRUD (por ejemplo, item-routes.js):
// Create new item router.post("/items", (req, res, next) => { Item.create({ title: req.body.title, description: req.body.description, owner: req.user._id // <-- AT THIS POINT, req.user is UNDEFINED }) .then( // ... ); });Registro de usuario e inicio de sesión:
class AuthService { constructor() { let service = axios.create({ baseURL: process.env.REACT_APP_API_URL, withCredentials: true }); this.service = service; } signup = (username, password) => { return this.service.post('/signup', {username, password}) .then(response => response.data) } login = (username, password) => { return this.service.post('/login', {username, password}) .then(response => response.data) } //... }Creando un nuevo elemento...:
axios.post(`${process.env.REACT_APP_API_URL}/items`, { title: this.state.title, description: this.state.description, }, {withCredentials:true}) .then( (res) => { // ... });No funcionaba como se esperaba porque estaba probando en Chrome Incognito y, de forma predeterminada, Chrome bloquea las cookies de terceros en modo Incognito ( más detalles ).
A continuación hay una lista con algunas cosas para verificar si tiene un problema similar;)
En caso de que ayude, aquí hay una lista de verificación con diferentes cosas que necesita principalmente;)
Si está implementando en Heroku, agregue la siguiente línea (puede agregarla antes de la configuración de su sesión).
app.set("trust proxy", 1); En particular, marca la opción sameSite y secure ( más detalles aquí ).
El siguiente código configurará sameSite: 'none' y secure: true en producción:
app.use( session({ secret: process.env.SESSION_SECRET || 'Super Secret (change it)', resave: true, saveUninitialized: false, cookie: { sameSite: process.env.NODE_ENV === "production" ? 'none' : 'lax', // must be 'none' to enable cross-site delivery secure: process.env.NODE_ENV === "production", // must be true if sameSite='none' } }) ); app.use( cors({ credentials: true, origin: [process.env.FRONTEND_APP_URL] }) );Configure las variables de entorno en Heroku. Por ejemplo:
FRONTEND_APP_URL = https://my-project.netlify.appIMPORTANTE : para la URL de CORS, evite una barra inclinada al final. Lo siguiente puede no funcionar:
FRONTEND_APP_URL = https://my-project.netlify.app/ --> avoid this trailing slash!Asegúrese de enviar credenciales en sus llamadas a la API (debe hacerlo para todas las llamadas que realice a la API, incluida la llamada para el inicio de sesión del usuario).
Si está usando axios, puede usar la opción withCredentials . Por ejemplo:
axios.post(`${process.env.REACT_APP_BACKEND_API_URL}/items`, { title: this.state.title, description: this.state.description, }, {withCredentials:true}) .then( (res) => { // ... });Para realizar pruebas, probablemente desee asegurarse de que está utilizando la configuración predeterminada proporcionada por cada navegador.
Por ejemplo, a partir de 2021, Chrome bloquea las cookies de terceros en modo de incógnito (pero no en modo "normal"), por lo que probablemente desee tener algo como esto:
Finalmente, tenga en cuenta que cada navegador tiene una política diferente para las cookies de terceros y, en general, se espera que esas restricciones aumenten en los próximos años.
Por ejemplo, se espera que Chrome bloquee las cookies de terceros en algún momento de 2023 ( fuente ).
Si su aplicación necesita eludir esas restricciones, aquí hay algunas opciones:
Implementar Backend y Frontend bajo el mismo dominio
Implemente Backend y Frontend bajo subdominios del mismo dominio (ejemplo, ejemplo.com y api.ejemplo.com)
Tenga su API de back-end bajo un proxy (si está usando Netlify, puede configurar fácilmente un proxy usando un archivo _redirects )