Search code examples
javascriptcookiesgraphqlapollo-client

Next Apollo Client Not Sending Cookies


So I have an Express / TypeGraphql backend running at localhost:5000 and Next / React app running at localhost:3000. I decided to use apollo-server for graphql API and apollo-client for the front end. After a successful login, I store httpOnly cookies in web browser.

What I want to do is, get cookies in every request and authorize the user if oauth2 tokens are valid. Even though requests are valid, and I get the query, cookies are shown as null. Also, I got no error in the console.

Here I save cookies =>

server.ts 

app.get('/auth/google/callback', function (req, res, next) {
    passport.authenticate('google', { session: false }, (err, user, info) => {
        if (err) return next(err);
        if (!user) return res.redirect('/');
        res.cookie('login_cookie', JSON.stringify(info), {
            secure: false,
            httpOnly: true,
            expires: dayjs().add(30, 'days').toDate(),
            sameSite: false,
        });
        return res.redirect('http://localhost:3000/home');
    })(req, res, next);
});

Here I log cookies to console after a request =>

resolver.ts

@Query(() => [User])
async users(@Ctx() ctx: Context) {
    console.log('cookies ', ctx.req.cookies);
    return await ctx.prisma.user.findMany();
}

and lastly, this is my apollo client config =>

apollo-client.ts

const client = new ApolloClient({
  cache: new InMemoryCache(),
  credentials: "include",
  uri: "http://localhost:5000/graphql",
});

After every request my console shows cookies: [Object: null prototype] {} even though I see them in browser's cookie storage.

request.ts

export async function getServerSideProps() {
const { data } = await client.query({
  query: gql`
    query allUsers {
      users {
        id
        username
      }
    }
  `,
});

return {
  props: {
    users: data.users,
  },
};

}


Solution

  • I think you have not fully understood Next.js yet. Next.js renders views on the server or alternatively sends "server-side props" to the client. This means getServerSideProps gets executed on the server (as the name suggests). Cookies are a feature of the browser. So what happens?

    1. Browser sends requests to Next.js. If your Next.js server and your GraphQL server are on the same domain, the request includes the Cookie header.
    2. Next.js receives request and executes getServeSideProps.
    3. Next.js Apollo Client makes a request to the server, missing the cookies because the cookies are only in the browser's initial request!

    This means you would have to first make sure that your Next.js server receives the cookies from the frontend. This should happen automatically if it is on the same origin as the GraphQL server. Otherwise, it is a bit tricky and it should be easier to work with an explicit Authorization header in this case. Then you have to pass on the cookies with the request. This can be done by accessing req in getServerSiteProps and using the context in client.query.

    export async function getServerSideProps(context) {
      const Cookie = context.req.headers.cookie;
      const { data } = await client.query({
        context: { headers: { Cookie } },
        query: gql`
          query allUsers {
            users {
              id
              username
            }
          }
        `,
      });
    
      return {
        props: {
          users: data.users,
        },
      };
    }
    

    Code is untested, but I think you get the idea.