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 =>
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 =>
@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 =>
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.
export async function getServerSideProps() {
const { data } = await client.query({
query: gql`
query allUsers {
users {
id
username
}
}
`,
});
return {
props: {
users: data.users,
},
};
}
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?
getServeSideProps
.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.