I have an app that’s built on react/next and a server built on express.
The basic flow is that a user authenticates via Github Oauth using passport.js, the server then returns a connect.sid cookie which should be used on subsequent requests to the server in order to render data to an authenticated user when they hit a protected endpoint.
As of now I can hit my authentication endpoint in the browser to obtain the cookie. And when I use the cookie in postman by adding it to the headers everything works as intended and the requested data is returned. Great!
The problem is now integrating it with a react/next app.
After authenticating I can see in the application tab that no connect.sid cookie is present, until after I fetch another protected endpoint, then it shows up. Not sure this is relevant or if it’s just not updating immediately.
When a fetch is triggered I notice in the network tab that there is no connect.sid cookie present in the header at all, and I’m not sure how to force the fetch to include it.
Here is my fetch
fetch(`api.invoice-app.naughty-cat.com/invoices/all`, {
withCredentials: true,
credentials: 'include'
})
.then(response => response.json())
.then(response => console.log(response))
.catch(err => console.log(err));
I have a suspicion it is related to either my cors config or session config, I have tried many combinations of settings without luck yet. I am sure I am missing some fundamental understanding about something here.
app.use(
cors({
credentials: true,
origin: '*'
})
);
app.use(
session({
secret: process.env.EXPRESS_SESSION_SECRET,
resave: false,
proxy: true,
saveUninitialized: false,
samesite: 'none',
secure: false,
cookie: { maxAge: 1000 * 60 *60 * 24
},
store: sessionStore
})
);
2
Answers
So I was able to finally figure out the proper settings with help from comments, answers, and other posts. I'll post things here in case it helps someone else in the future.
First here is the fetch, making sure to include credentials:
Here is my cors setup":
And here are my session settings, the meat and potatoes of the post:
The trick for me was the cookie settings depending on where things are being hosted.
When the server is hosted on some external domain, but the front end is on localhost for development then sameSite: "none" and secure: true settings will allow the cookie to be sent in fetches (though I think this will soon be disallowed by browsers as they are all blocking third party cookies soon)? For this reason I have left it out.
When the server and the front end are both hosted on localhost then the settings sameSite: lax and secure: auto will work (since you likely wont have ssl on localhost).
When the server and front end are both hosted on the same domain (i.e. for production) then sameSite: lax and secure: true are the settings you will likely be wanting to allow the cookies to be passed.
I have a check in my code now for the environment (dev or prod) which sets things depending on that.
I see possible two issues here.
withCredentials
origin: '*'
. This setting does not work when credentials are included in cross-origin requests. You must specify an explicit origin instead of using *. For local development, this should be the URL of your React/Next.js app, for example,http://localhost:3000
. Update your Express server’s CORS configuration like belowUPDATE
There is no
withCredentials
option inside thefetch()
. It should be onlycredentials:"include"
. Look at this LinkSo your
fetch()
should be