TL;DR fetch API is the successor of XHR and although it's really powerful ( see What is the difference between the Fetch API and XMLHttpRequest?) you should take care of some things, like the fact you are responsible to determine if cookies must be sent to the server.
This is not a tutorial on how to use the fetch
API neither Express framework. This post is a short reminder on how to work with cookies in an Express application that uses fetch in the client side.
Before continue I'm going to describe my application scenario so you can be centered in the problem produced me a real headache.
credentials
propertySimply remember you must use the credentials property to send cookies in your requests.
The credentials read-only property of the Request interface indicates whether the user agent should send cookies from the other domain in the case of cross-origin requests. This is similar to XHR’s withCredentials flag.
The allowed values are:
omit
: Never send cookies. Default value.same-origin
: Only send cookies if the URL is on the same origin as the calling script.include
: Always send cookies, even for cross-origin calls.So, you must set the credentials
property in all your client requests so that any operation, a login, an operation that retrieves resources or creates a new resource, sends the cookie to the API and can be authenticated. In my case I choose credentials: same-origin
.
Note, if your API is in a different domain that the page that serves your client code you must use the mode property too to indicate a CORS request.
On the server side, the API, we have configured Express to allow sessions and configured passport to store local authentication in sessions. It is important to remember initialize the passport session middleware after the express session one.
import session from 'express-session';
import passport from 'passport';
app.use(session({
resave: false,
saveUninitialized: false,
secret: 'supersecret',
cookie: {
httpOnly: false,
secure: false,
},
}));
app.use(passport.initialize());
app.use(passport.session());
if (app.get('env') === 'production') {
app.set('trust proxy', 1); // trust first proxy
sessionOptions.proxy = true;
sessionOptions.cookie.secure = true; // serve secure cookies
}
Lets describe the previous session configuration properties:
cookies
: this object contains configuration on how cookies must be handled in the session.
secure
: Specified if Set-Cookie
header will contains Secure
flag. Be careful when setting this to true, as compliant clients will not send the cookie back to the server in the future if the browser does not have an HTTPS connection.httpOnly
: Specified if Set-Cookie
header will contains HttpOnly
flag. Be careful when setting this to true, as compliant clients will not allow client-side JavaScript to see the cookie in document.cookie.This two cookies
properties can become your worst enemy while developing because usually you do not work using HTTPS. So, take them into account.
As always the process of developing is a cycle of pain and ecstasy, where pain is almost always produced by stupid or really subtle things that transform your productive day in a hell.