next-with-apollo icon indicating copy to clipboard operation
next-with-apollo copied to clipboard

Cookie Disappearing after reload

Open guiaramos opened this issue 4 years ago • 0 comments

Hi there, I have an issue on production env. When reloading page the cookie is being deleted, I think this issue would be related to the lib because of this similar issue: https://github.com/vercel/next.js/discussions/12982#discussioncomment-22513

Does anyone know how to fix it? Perhaps wrong settings?

web

package.json

{
    "next": "^9.4.0",
    "next-cookies": "^2.0.3",
    "next-fonts": "^1.0.3",
    "next-with-apollo": "^5.0.1",
    "apollo-boost": "^0.4.7",
    "apollo-cache": "^1.3.4",
    "apollo-cache-inmemory": "^1.6.5",
    "apollo-cache-persist": "^0.1.1",
    "apollo-client": "^2.6.8",
    "apollo-link": "^1.2.14",
    "apollo-link-context": "^1.0.19",
    "apollo-link-error": "^1.1.13",
    "apollo-link-http": "^1.5.16",
    "apollo-link-token-refresh": "^0.2.7",
}

withApollo.ts

export default withApollo(
  ({ initialState, ctx, headers }) => {
    console.log('host: ', process.env.NEXT_PUBLIC_BACKEND_HOST);
    const ssrMode = !process.browser;
    const getToken = async () => {
      let serverAccessToken = '';

      if (isServer()) {
        const stringCookies = headers?.cookie;
        if (stringCookies) {
          const cookies = cookie.parse(headers?.cookie || '');
          if (cookies.jid) {
            const response = await axios(ENDPOINTS.REFRESH_TOKEN, {
              method: 'POST',
              withCredentials: true,
              headers
            });
            const data = await response.data;
            serverAccessToken = data.accessToken;
          }
        }
      }

      return serverAccessToken;
    };

    const httpLink: ApolloLink = new HttpLink({
      uri: `${ENDPOINTS.GRAPHQL}`,
      credentials: 'include',
      fetch
    });

    const refreshLink = new TokenRefreshLink({
      accessTokenField: 'accessToken',
      isTokenValidOrUndefined: () => {
        const token = getAccessToken();

        if (!token) {
          return true;
        }

        try {
          const { exp } = jwtDecode(token);
          if (Date.now() >= exp * 1000) {
            return false;
          }
          return true;
        } catch {
          return false;
        }
      },
      fetchAccessToken: () => {
        return fetch(ENDPOINTS.REFRESH_TOKEN, {
          method: 'POST',
          credentials: 'include'
        });
      },
      handleFetch: (accessToken) => {
        setAccessToken(accessToken);
      },
      handleError: () => {
        console.warn('Your refresh token is invalid. Try to relogin');
      }
    });

    const authLink = setContext(async (_request, { headers: authHeaders }) => {
      const token = isServer() ? await getToken() : await getAccessToken();

      return {
        headers: {
          ...authHeaders,
          authorization: token ? `Bearer ${token}` : ''
        }
      };
    });

    const errorLink = onError(({ graphQLErrors, networkError }) => {
      if (graphQLErrors)
        graphQLErrors.forEach(({ message, locations, path, extensions }) => {
          switch (extensions!.code) {
            case 'UNAUTHENTICATED': {
              // error code is set to UNAUTHENTICATED
              // when AuthenticationError thrown in resolver

              // modify the operation context with a new token
              // TODO: Should work on server-side aswell
              redirect(ctx, '/login');
              break;
            }
            default:
              console.error(
                `[GraphQL error]: Code: ${
                  extensions!.code
                } Message: ${message}, Location: ${locations}, Path: ${path}`
              );
          }
        });
      if (networkError) {
        // if you would also like to retry automatically on
        // network errors, we recommend that you use
        // apollo-link-retry

        if (!isServer()) redirect(ctx, '/maintance');
      }
    });

    let link = httpLink;
    if (!ssrMode) {
      // Create a WebSocket link:
      const wsLink = new WebSocketLink({
        uri: `ws://${process.env.NEXT_PUBLIC_BACKEND_HOST}:${process.env.NEXT_PUBLIC_BACKEND_PORT}/graphql`,
        options: {
          reconnect: true
        },
        webSocketImpl: WebSocket
      });

      link = split(
        ({ query }) => {
          const def = getMainDefinition(query);
          return def.kind === 'OperationDefinition' && def.operation === 'subscription';
        },
        wsLink,
        httpLink
      );
    }

    const cache = new InMemoryCache().restore(initialState || {});
    return new ApolloClient({
      ssrMode: typeof window === 'undefined', // Disables forceFetch on the server (so queries are only run once)
      link: ApolloLink.from([refreshLink, authLink, errorLink, link]),
      cache
    });
  },
  {
    // eslint-disable-next-line react/display-name
    render: ({ Page, props }) => {
      return (
        // eslint-disable-next-line react/destructuring-assignment
        <ApolloProvider client={props.apollo}>
          <Page {...props} />
        </ApolloProvider>
      );
    }
  }
);

server

package.json

{
    "apollo-server-express": "^2.11.0",
}

send token function

import { Response } from 'express';
  function sendRefreshToken(res: Response, token: string): void {
    res.cookie('jid', token, {
      httpOnly: true
    });
  }

guiaramos avatar Jul 11 '20 07:07 guiaramos