Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to implement CSRF protection in Nextjs with Apollo and GraphQL

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.

like image 218
The_Wolf Avatar asked Jan 13 '19 11:01

The_Wolf


People also ask

Does Nextjs support GraphQL?

They also make and maintain a GraphQL client (Apollo Client) that we can use with React frameworks like Next. js. The Apollo Client is a state management client that allows you to manage both local and remote data with GraphQL and you can use it to fetch, cache, and modify application data.

How do I enable CORS in Apollo client?

You can enable credentials with CORS by setting the Access-Control-Allow-Credentials HTTP header to true . You must specify an origin to enable credentialed requests. If your server sends the * wildcard value for the Access-Control-Allow-Origin HTTP header, your browser will refuse to send credentials.

What is Gql in Apollo server?

GraphQL serverA server that contains a GraphQL schema and can resolve operations that are executed against that schema. Apollo Server is an example of a GraphQL server.


1 Answers

Update

After so much browsing i finally was able to send csrf cookie. I think the problem lies with with the word return.When you use return it excludes the cookie. This is what i did by editing /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}` : "",
          "x-xsrf-token": csrfToken ? csrfToken : ""
        }
        cookies: {
          ...cookies
        }
      };
    });
  });

pree!! However SSR does not have cookies. I think we should have two endpoint from client and another for SSR. The SSR url can be csrf exempted.

like image 174
Ngatia Frankline Avatar answered Sep 23 '22 03:09

Ngatia Frankline