SSR - Send request with cookie from apollo client with Next.js
See original GitHub issueplease help, I tried all the examples and also other tutorials on the internet but no luck to fix the problem. I am using apollo client to get the data and I am using a cookie or Bearer (which one works) for authentication but in the first request and after every refresh, it is sending request with no cookie or Bearer in it, and my API rejects the request but in the second request which it happen immediately (automatically by app NOT user) after the first one it includes cookie and Bearer on it.
I think:
- the first request is coming from the server (which doesn’t have access to cookie)
- the second request is from the client (has access to cookie)
I tried to force the component to render just in client-side but no luck on it here is init-apollo.tsx file:
import { ApolloClient, InMemoryCache } from "apollo-boost";
import fetch from "isomorphic-unfetch";
import { setContext } from "apollo-link-context";
import { createHttpLink } from "apollo-link-http";
import { variables } from "./variables";
import { auth } from "./auth";
import { isBrowser } from "./utils";
let apolloClient = null;
function create(initialState, { fetchOptions }) {
const httpLink = createHttpLink({
uri: variables.apiUri,
credentials: "include",
fetch: isBrowser ? fetch : undefined,
fetchOptions
});
const authLink = setContext((_, { headers }) => {
const token = auth.getUserToken();
return {
headers: {
...headers,
authorization: token ? `Bearer ${token}` : ""
}
};
});
return new ApolloClient({
connectToDevTools: isBrowser,
ssrMode: false,
link: authLink.concat(httpLink),
cache: new InMemoryCache().restore(initialState || {}),
ssrForceFetchDelay: 100
});
}
here is my withApollo.tsx code:
import React from "react";
import cookie from "cookie";
import initApollo from "./init-apollo";
import Head from "next/head";
import { getDataFromTree } from "react-apollo";
function parseCookies(req, options = {}) {
return cookie.parse(
req ? req.headers.cookie || "" : document.cookie,
options
);
}
export default App => {
return class WithApollo extends React.Component {
public constructor(props) {
super(props);
this.apolloClient = initApollo(props.apolloState, {
getToken: () => {
return parseCookies(undefined).token;
}
});
}
public apolloClient = undefined;
public static displayName = "withApollo(App)";
public static async getInitialProps(ctx) {
const {
Component,
router,
ctx: { req, res }
} = ctx;
const apollo = initApollo(
{},
{
getToken: () => parseCookies(req).token
}
);
ctx.ctx.apolloClient = apollo;
let appProps = {};
if (App.getInitialProps) {
appProps = await App.getInitialProps(ctx);
}
if (res && res.finished) {
// When redirecting, the response is finished.
// No point in continuing to render
return {};
}
if (typeof window === "undefined") {
try {
// Run all GraphQL queries
await getDataFromTree(
<App
{...appProps}
Component={Component}
router={router}
apolloClient={apollo}
/>
);
} catch (error) {
// Prevent Apollo Client GraphQL errors from crashing SSR.
// Handle them in components via the data.error prop:
// https://www.apollographql.com/docs/react/api/react-apollo.html#graphql-query-data-error
console.error("Error while running `getDataFromTree`", error);
}
// getDataFromTree does not call componentWillUnmount
// head side effect therefore need to be cleared manually
Head.rewind();
}
// Extract query data from the Apollo store
const apolloState = apollo.cache.extract();
return {
...appProps,
apolloState
};
}
public render() {
return <App {...this.props} apolloClient={this.apolloClient} />;
}
};
};
and _app.tsx file:
import React from "react";
import App, { Container } from "next/app";
import { runWithAdal } from "react-adal";
import { authContext } from "../helpers/adal-config";
import AppLayout from "../components/common/AppLayout";
import GlobalContext from "../helpers/global-context";
import { auth } from "../helpers/auth";
import withApollo from "../helpers/with-apollo";
import { ApolloProvider } from "react-apollo";
class MyApp extends App {
public state = {
isLoggedIn: auth.getUserProfile() ? true : false,
userProfile: auth.getUserProfile(),
logout: () => {
auth.logOut();
}
};
public static async getInitialProps({ Component, ctx }) {
let pageProps = {};
if (Component.getInitialProps) {
pageProps = await Component.getInitialProps(ctx);
}
return { pageProps };
}
public render() {
// @ts-ignore
const { Component, pageProps, apolloClient } = this.props;
return (
<Container>
<ApolloProvider client={apolloClient}>
<GlobalContext.Provider value={this.state}>
<AppLayout>
<Component {...pageProps} />
</AppLayout>
</GlobalContext.Provider>
</ApolloProvider>
</Container>
);
}
}
/** @false: Login when app loads
* @true: do not login when app loads (wait for other components to ask for login)
*/
const doNotLogin = false;
runWithAdal(
authContext,
() => {
return MyApp;
},
doNotLogin
);
export default withApollo(MyApp);
My Component:
import { Query } from "react-apollo";
import gql from "graphql-tag";
import Loading from "./common/Loading";
import Error from "./common/Error";
import { isBrowser } from "../helpers/utils";
const helloQuery = gql`
query hello {
hello
}
`;
const PostList = function PostList() {
return (
<Query query={helloQuery} ssr={false}>
{({ loading, error, data }) => {
if (error) {
return <Error />;
}
if (loading) {
return <Loading />;
}
return <section>{data.hello as string}</section>;
}}
</Query>
);
};
export default PostList;
Issue Analytics
- State:
- Created 4 years ago
- Reactions:6
- Comments:35 (2 by maintainers)
Top Results From Across the Web
Next.js With Apollo, SSR, Cookies, and Typescript
In this blog post I'll show you how I created a working Next.js TypeScript setup with Apollo Client. You can fetch data from...
Read more >Server-side rendering - Apollo GraphQL Docs
Server-side rendering (SSR) is a performance optimization for modern web apps. It enables you to render your app's initial state to raw HTML...
Read more >Next.js: React Apollo Client Not sending cookies?
Surprisingly, when I make a mutation to the graphql server I'm able to set the cookies but, I'm not able to get the...
Read more >Client and Server Side Cookies in Next.js - YouTube
Let's learn how to set/remove cookies both in the browser but also on the server in Next. js. This will allow us to...
Read more >Using cookies to authenticate Next.js + Apollo GraphQL ...
Using cookies to authenticate Next.js + Apollo GraphQL requests ; // pages/api/graphql/index.ts // https://github.com/zeit/next.js/blob/master/ ...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Here’s my modification of the official nextjs example, which passing the cookie from nextjs ctx to fetch on ssr.
The newest nextjs example works with a seperate apolloClient.js file. Modified it like so (based on mzygmunt’s code).