1
votes

I'm trying to build SSR application using NextJS and apollo-client on the frontend, and graphql with express using (graphQL Yoga) on the backend.

I came from client side rendering background and things there are simpler than SSR when it comes to authentication, in regular client side rendering my approach to authenticate user was like:

1- once the user login after server validation, sign a JWT with current user data, then send it to the client side, and save it in localstorage or cookies, etc...

2- implement a loadUser() function and call it in the (root) App component's useEffect hook to load the user in every component (page) if the JWT in localstorage is valid.

3- if the JWT isn't there or is invalid just return user as null and redirect to login page.

so in Next.js i know we can't access localstorage cause it works server side, so we just save the token in a cookie, and the approach i implemented is painful and i was wondering if there is an pimplier way, my approach is like: 1- once the user login he calls the login mutation which sets a cookie in the req header, and return a user and any data i want. 2- in each page that requires authentication i need to get the token from the cookie to send it back in the header and i did that in getInitialProps() or getServerSideProps() cause both runs server side and have access to the request cookies in the header like so:

export const getServerSideProps = async ctx => {
  const apolloClient = initializeApollo();

  // get the cookies from the headers in the request object
  const token = ctx.req.headers.cookie ? ctx.req.headers.cookie : null;
  return {
    props: {
      initialApolloState: apolloClient.cache.extract(),
      token: token
    }
  };
};

now i have access to the token in the page props and can send the token back with the req header with my apollo client like so:

let getUserQuery = await apolloClient.query({
    query: GET_USER_QUERY,
    variables: { id: ctx.params.id },
    context: { headers: { token: token } }
  });

now i have access to the token in the server side request like req.headers.token

what i wanna achieve:

1- is there an easier way to implement loadUser() that loads the user with every page render that i can implement in next.js custom _app , i found this answer but it doesn't return auth object or user in all components as he mentioned in his answer.

2- i read that if i set cookies httpOnly and credentials: "include" i have access to cookie in every request, but it seems that it doesn't work with apollo client, that would be awesome if there is an alternative approach.

3- there is apollo-link-context provided by apollo team where i can send a token or any value in every request's header using setContext() like so:

const authLink = setContext((_, { headers }) => {
  // get the authentication token from local storage if it exists
  const token = localStorage.getItem('token');
  // return the headers to the context so httpLink can read them
  return {
    headers: {
      ...headers,
      authorization: token ? `Bearer ${token}` : "",
    }
  }
});

but since i don't have access to localstorage i can't implement it cause next runs server side, so if anyone has an implementation for this please consider sharing.

PS. i made this thread after searching and reading for like 1 week and it's my last resort to ask you guys, and thanks in advance.

1
hi, did you get any solution the best way to integrate apollo client with Next.js?Shubham Kumar
@ShubhamKumar hi Shubham, what i did was: 1- once the user logs in i save the JWT in a cookie, cause you don't have access to localstorage in nextJs. 2- in your custom _app getInitialProps() you have access to the cookie through ctx.req.headers.cookie -using GQL and apollo i made a query that fetches the current logged in user if there's a logged in user and called it me i sent the fetched data from that query in the _app and you can get it like let me = props.meQuery; and send it to all comp <Component {...pageProps} {...me} /> check it here github.com/hamohuh/social-apphamohuh

1 Answers

0
votes

get token by store store.getState()..path.to.your.token

the problem is that the token doesn't completely update when the blind changes and I'm looking for a solution.