Following this example in Nextjs repository, I want to implement the CSRF protection (perhaps with csurf package), because I'm using a session ID cookie with express-session.
I tried setting csurf in my custom server and save the generated token in res.locals.csrfToken which can be taken, on first page load, by the static method "getInitialProps" which is located in /lib/withApollo.js in the example I linked. As soon as I try to change page (with links) or try to make a post request with apollo (login, for instance), server changes the csrf token, so the one which was used by Apollo is no more useful and so I get a "csrf is invalid" error.
Custom server with csurf configuration
const csrf = require('csurf');
const csrfProtection = csrf();
////express-session configuration code////
app.use(csrfProtection);
app.use((req, res, next) => {
res.locals.csrfToken = req.csrfToken();
next();
})
/lib/initApollo.js
function create(initialState, { getToken, cookies, csrfToken }) {
const httpLink = createHttpLink({
uri: "http://localhost:3000/graphql",
credentials: "include"
});
const authLink = setContext((_, { headers }) => {
const token = getToken();
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : "",
Cookie: cookies ? cookies : "",
"x-xsrf-token": csrfToken ? csrfToken : ""
}
};
});
/lib/withApollo.js
static async getInitialProps(ctx) {
const {
Component,
router,
ctx: { req, res }
} = ctx;
const apollo = initApollo(
{},
{
getToken: () => parseCookies(req).token,
cookies: req ? req.headers.cookie : "",
csrfToken: res ? res.locals.csrfToken : document.cookie
}
);
With this config, every route is protected against csrf, but the token created on the server often change and Apollo can't retrieve the updated one as soon as it needs, so the first load is successful, but the subsequent page change (links) or any post request fails, because the token has changed.