Next.js & Apollo: Troubleshooting Cookies Not Being Passed in Your HOC Configuration

Next.js and Apollo Client are a powerful duo for building modern, data-driven web applications. Next.js excels at server-side rendering (SSR), static site generation (SSG), and client-side navigation, while Apollo Client simplifies managing GraphQL data fetching, caching, and state. However, one common roadblock developers face is cookies not being passed correctly in Higher Order Component (HOC) configurations. This issue can break critical flows like authentication, session management, or personalized content—leaving users frustrated with "unauthorized" errors or missing data.

Cookies are often used to store JWT tokens, session IDs, or user preferences, making their reliable transmission between client and server essential. HOCs, which wrap components to inject data or functionality (e.g., withApollo for GraphQL data fetching), can inadvertently disrupt cookie flow if misconfigured, especially when mixing client-side and server-side rendering (SSR) in Next.js.

In this guide, we’ll demystify why cookies fail to pass in HOC setups, walk through step-by-step troubleshooting, and provide actionable solutions to ensure your cookies are transmitted reliably.

Table of Contents#

  1. Understanding the Problem: Why Cookies Matter in Next.js & Apollo
  2. Common Causes of Cookies Not Being Passed in HOCs
  3. Troubleshooting Steps: Diagnosing the Issue
  4. Step-by-Step Solution: Fixing Cookie Passing in HOCs
  5. Advanced Scenarios: Edge Cases and Workarounds
  6. Conclusion
  7. References

1. Understanding the Problem: Why Cookies Matter in Next.js & Apollo#

Before diving into solutions, let’s clarify why cookies are critical and how their transmission can fail in HOCs.

What Are Cookies Used For?#

Cookies are small pieces of data stored in the user’s browser, sent automatically with every HTTP request to the server. In Next.js + Apollo apps, they’re often used for:

  • Authentication: Storing JWT tokens, session IDs, or OAuth tokens.
  • Personalization: Tracking user preferences (e.g., theme settings).
  • Server-Side Context: Passing metadata (e.g., A/B test groups) to the server.

HOCs like withApollo or custom data-fetching HOCs wrap components to inject GraphQL data. For cookies to work, they must be included in:

  • Client-side requests: Apollo Client sends cookies from the browser to the GraphQL server.
  • Server-side requests: Next.js (during SSR/SSG) sends cookies from the incoming HTTP request to the GraphQL server.

When cookies aren’t passed, the GraphQL server can’t authenticate the user, leading to 401 Unauthorized errors, missing user-specific data, or broken sessions.

2. Common Causes of Cookies Not Being Passed in HOCs#

To fix the issue, first identify its root cause. Here are the most frequent culprits:

2.1 Apollo Client Configuration Issues#

Apollo Client doesn’t send cookies by default. If you forget to configure credentials, cookies will never reach the server. Key misconfigurations include:

  • Missing credentials setting in HttpLink (e.g., not setting credentials: 'include' or 'same-origin').
  • Using Apollo Boost (deprecated) without explicitly enabling credentials.
  • Overriding headers in context links (e.g., setContext) and accidentally stripping cookies.

2.2 Next.js Server-Side vs. Client-Side Rendering Differences#

Next.js has distinct data-fetching patterns (SSR, SSG, CSR), and cookies behave differently in each:

  • SSG (getStaticProps): Runs at build time, with no access to the incoming request. Cookies (user-specific) can’t be used here.
  • SSR (getServerSideProps): Runs per request, with access to req.headers.cookie. If HOCs use getStaticProps instead of getServerSideProps, cookies are unavailable.
  • Client-side rendering (CSR): Relies on the browser’s cookie store, but Apollo Client may not send them without credentials: 'include'.

2.3 HOC Implementation Pitfalls#

HOCs can inadvertently block cookies if:

  • They hardcode data-fetching logic to use getStaticProps (unsuitable for dynamic, user-specific data).
  • They fail to pass server-side cookies from getServerSideProps to Apollo Client.
  • They use outdated patterns (e.g., withApollo HOCs not compatible with Next.js 13+ App Router).

2.4 CORS and Server Configuration#

Even if the client sends cookies, the server may reject them due to misconfigured CORS:

  • Missing Access-Control-Allow-Credentials: true header on the GraphQL server.
  • Using Access-Control-Allow-Origin: '*' with credentials (browsers block this—origin must be explicit).
  • Mismatched domains (e.g., client on http://localhost:3000 and server on https://api.example.com without CORS allowlisting).

3. Troubleshooting Steps: Diagnosing the Issue#

Use these steps to pinpoint where cookies are getting stuck:

3.1 Check Network Requests (Client-Side)#

Use your browser’s DevTools (Network tab) to inspect Apollo Client requests:

  • Filter for GraphQL requests (look for POST to your GraphQL endpoint).
  • Check the Request Headers for a Cookie field. If missing, Apollo Client isn’t sending cookies.
  • Check the Response Headers for Set-Cookie (if the server is supposed to set cookies) and Access-Control-Allow-Credentials: true.

3.2 Inspect Server-Side Requests (Next.js SSR)#

For server-side requests (e.g., during SSR), log the incoming cookies in getServerSideProps:

// pages/protected-page.js
export async function getServerSideProps(ctx) {
  console.log("Server-side cookies:", ctx.req.headers.cookie); // Check if cookies appear here
  return { props: {} };
}

If ctx.req.headers.cookie is empty, cookies aren’t reaching Next.js’s server. If it’s populated but Apollo Client still fails, the HOC isn’t passing them to Apollo.

3.3 Verify Apollo Client Setup#

Audit your Apollo Client configuration. Ensure:

  • HttpLink includes credentials: 'include' (for cross-origin requests) or 'same-origin' (for same-domain requests).
  • No conflicting headers are stripping cookies (e.g., in setContext):
    // Bad: Overriding headers without preserving existing ones
    const authLink = setContext((_, { headers }) => ({
      headers: {
        authorization: `Bearer ${token}`, // Accidentally removes cookies!
      },
    }));
     
    // Good: Merge with existing headers
    const authLink = setContext((_, { headers }) => ({
      headers: {
        ...headers, // Preserves cookies and other headers
        authorization: `Bearer ${token}`,
      },
    }));

3.4 Review HOC Data Fetching Logic#

Check if your HOC uses the right data-fetching method:

  • If the HOC wraps a page using getStaticProps, switch to getServerSideProps (SSG can’t access request cookies).
  • Ensure the HOC passes server-side cookies from getServerSideProps to Apollo Client (see Section 4 for examples).

Follow these steps to ensure cookies are passed reliably in your HOC.

4.1 Configure Apollo Client with Credentials#

First, ensure Apollo Client sends cookies in all requests. Use createHttpLink with credentials enabled:

// lib/apollo-client.js
import { ApolloClient, InMemoryCache, createHttpLink } from '@apollo/client';
import { setContext } from '@apollo/client/link/context';
 
// 1. Create HTTP link with credentials
const httpLink = createHttpLink({
  uri: 'https://your-graphql-server.com/graphql', // Your GraphQL endpoint
  credentials: 'include', // Critical: Sends cookies in client-side and server-side requests
});
 
// 2. Optional: Add auth headers (merge with existing headers!)
const authLink = setContext((_, { headers }) => ({
  headers: {
    ...headers, // Preserve existing headers (including cookies)
    // Add custom headers here (e.g., API keys)
  },
}));
 
// 3. Initialize Apollo Client
export function createApolloClient() {
  return new ApolloClient({
    link: authLink.concat(httpLink), // Combine links
    cache: new InMemoryCache(),
  });
}

4.2 Handle SSR/SSG in Next.js with Cookies#

For server-side rendering, pass cookies from getServerSideProps to Apollo Client. Use a withApollo HOC to inject cookies into server-side requests:

// lib/withApollo.js
import { ApolloProvider } from '@apollo/client';
import { createApolloClient } from './apollo-client';
 
export function withApollo(PageComponent) {
  const WithApollo = ({ apolloClient, pageProps }) => (
    <ApolloProvider client={apolloClient}>
      <PageComponent {...pageProps} />
    </ApolloProvider>
  );
 
  // 1. Server-side: Fetch data with cookies from the request
  WithApollo.getServerSideProps = async (ctx) => {
    const { req } = ctx;
    const apolloClient = createApolloClient();
 
    // 2. Pass server-side cookies to Apollo Client
    if (req) {
      // Inject cookies into Apollo's HTTP link headers
      apolloClient.link.options.headers.cookie = req.headers.cookie || '';
    }
 
    // 3. Fetch data (if the page has getServerSideProps)
    const pageProps = await PageComponent.getServerSideProps?.(ctx) || {};
 
    return {
      ...pageProps,
      props: {
        ...pageProps.props,
        apolloClient: apolloClient, // Pass client to the component
      },
    };
  };
 
  return WithApollo;
}

4.3 Correct HOC Implementation for Data Fetching#

Use the withApollo HOC in your page components, and ensure you use getServerSideProps for dynamic, cookie-dependent data:

// pages/protected-page.js
import { useQuery } from '@apollo/client';
import { withApollo } from '../lib/withApollo';
import { GET_USER_DATA } from '../graphql/queries';
 
function ProtectedPage() {
  // Client-side: Apollo sends cookies automatically (thanks to `credentials: 'include'`)
  const { data, error } = useQuery(GET_USER_DATA);
 
  if (error) return <div>Error: {error.message}</div>;
  if (!data) return <div>Loading...</div>;
 
  return <h1>Welcome, {data.user.name}!</h1>;
}
 
// Wrap the page with Apollo HOC to handle SSR/CSR cookies
export default withApollo(ProtectedPage);
 
// Use getServerSideProps to ensure cookies are available server-side
export async function getServerSideProps(ctx) {
  return { props: {} }; // Apollo HOC will handle data fetching
}

4.4 Ensure CORS and Server Compatibility#

Your GraphQL server must allow credentials. For example, with an Express server:

// Express server (GraphQL API)
const express = require('express');
const cors = require('cors');
const app = express();
 
app.use(cors({
  origin: 'https://your-nextjs-app.com', // Explicit origin (not '*'!)
  credentials: true, // Critical: Allows cookies
}));
 
// Start server
app.listen(4000, () => console.log("GraphQL server running on port 4000"));

5. Advanced Scenarios: Edge Cases and Workarounds#

5.1 Using getServerSideProps with HOCs in Next.js 13+ App Router#

Next.js 13+ App Router uses React Server Components (RSC) by default. For HOCs in the App Router:

  • Use async components with fetch or Apollo Client’s fetchQuery (no HOCs needed for data fetching).
  • Access cookies via cookies() from next/headers:
    // app/protected-page/page.js
    import { getServerSession } from "next-auth/next";
    import { cookies } from "next/headers";
     
    export default async function ProtectedPage() {
      const sessionCookie = cookies().get("session")?.value; // Access cookies
      // Fetch data with Apollo Client using sessionCookie
      return <div>Protected Content</div>;
    }

Next.js Middleware can modify cookies (e.g., adding/removing them). If cookies disappear, check for conflicting middleware:

// middleware.js
export function middleware(req) {
  const response = NextResponse.next();
  // Avoid removing cookies accidentally:
  response.cookies.set("session", req.cookies.get("session")?.value); // Preserve cookies
  return response;
}

5.3 Apollo Client 3+ Specific Considerations#

Apollo Client 3+ requires explicit defaultOptions for query policies. Ensure fetchPolicy doesn’t bypass the network (which skips cookie transmission):

const client = new ApolloClient({
  // ... other config
  defaultOptions: {
    watchQuery: {
      fetchPolicy: 'cache-and-network', // Ensures fresh data (with cookies)
    },
  },
});

6. Conclusion#

Cookies not being passed in Next.js + Apollo HOC configurations is a common issue, but it’s solvable with careful setup. Key takeaways:

  • Configure Apollo Client with credentials: 'include' in HttpLink.
  • Use getServerSideProps for dynamic, user-specific data (avoids SSG’s build-time limitations).
  • Pass server-side cookies from req.headers.cookie to Apollo Client in your HOC.
  • Fix CORS on the GraphQL server (explicit origin and credentials: true).

By addressing these areas, you’ll ensure cookies flow reliably between the browser, Next.js, and your GraphQL server—keeping authentication and sessions working seamlessly.

7. References#