SSR: clerk with hasura
Tags: clerk, hasura, graphql, nextjs
Published: 2022-07-21 13:50:00

This article will help you in achieving server side rendering(authentication) with clerk(withServerSideAuth) in next.js

**[Clerk](https://clerk.dev/)**
Multiple authentication strategies are available through Clerk so that legitimate users can access your application and make authenticated requests

**Into SSR with Nextjs and Clerk**
To enable server-side rendering, Nextjs uses a special export named getServerSideProps. WithServerSideAuth helper from clerk is populated with the auth singleton.

_steps:_
1. setup an apollo client 
2. use getServerSideProps and withServerSideAuth for ssr 
3. use graphql query
4. test for both authenticated and non-authenticated user
5. if there is a condition where your query is meant to response only after login then please do not return anything otherwise it will lead to issues

_code snippet for same:_

######1.apolloclient setup:###### 
```
import { useMemo } from 'react';
import { ApolloClient, createHttpLink, InMemoryCache } from '@apollo/client';
import merge from 'deepmerge';
import isEqual from 'lodash/isEqual';

let apolloClient;
const uri = process.env.NEXT_PUBLIC_HASURA_URI;
function createApolloClient(headers) {
  return new ApolloClient({
    ssrMode: typeof window === 'undefined', // set to true for SSR
    link: createHttpLink({
      uri,
      credentials: 'same-origin',
      headers: {
        Apitoken: process.env.YOUR_API_TOKEN,
      },
    }),
    cache: new InMemoryCache({
      typePolicies: {
        Query: {
          fields: {
            feed: {
              keyArgs: ['strategy', 'limit', 'gt_token'],
              // Concatenate the incoming list items with
              // the existing list items.
              merge(existing = [], incoming) {
                const result = Object.assign({}, incoming);
                if (existing?.hits) {
                  result.hits = [...existing.hits, ...incoming.hits];
                }
                return result;
              },
            },
            experts: {
              keyArgs: ['limit'],
              // Concatenate the incoming list items with
              // the existing list items.
              merge(existing = [], incoming) {
                const result = Object.assign({}, incoming);
                if (existing?.hits) {
                  result.hits = [...existing.hits, ...incoming.hits];
                }
                return result;
              },
            },
          },
        },
      },
    }),
  });
}

export function initializeApollo(initialState = null, ctx) {
  const headers = ctx?.headers ?? {};
  const _apolloClient = apolloClient ?? createApolloClient(headers);

  // If your page has Next.js data fetching methods that use Apollo Client,
  // the initial state gets hydrated here
  if (initialState) {
    // Get existing cache, loaded during client side data fetching
    const existingCache = _apolloClient.extract();

    // Restore the cache using the data passed from
    // getStaticProps/getServerSideProps combined with the existing cached data
    const data = merge(initialState, existingCache, {
      // combine arrays using object equality (like in sets)
      arrayMerge: (destinationArray, sourceArray) => [
        ...sourceArray,
        ...destinationArray.filter((d) =>
          sourceArray.every((s) => !isEqual(d, s))
        ),
      ],
    });
    _apolloClient.cache.restore(data);
  }

  // For SSG and SSR always create a new Apollo Client
  if (typeof window === 'undefined') return _apolloClient;

  // Create the Apollo Client once in the client
  if (!apolloClient) apolloClient = _apolloClient;
  return _apolloClient;
}

export function useApolloHasura(initialState) {
  return useMemo(
    () => initializeApollo(initialState, undefined),
    [initialState]
  );
}
```

######2.use getServerSideProps and withServerSideAuth for ssr:######
```
import { initializeApollo } from '../apolloClient';
import { withServerSideAuth } from '@clerk/nextjs/ssr';

export const getServerSideProps = withServerSideAuth(
  async (ctx) => {
   const { getToken } = ctx.req.auth;
    const token = await getToken({ template: 'hasura' });
    const apolloClient = initializeApollo(null, ctx);

   const client = initialApollo(null, ctx);
    const sub =
      (await client.query({
        query: YOUR_QUERY,
        context: {
          headers: {
            authorization: 'YOUR_AUTHORIZATION_TOKEN',
          },
        },
      }));

    const status = sub?.data;

       return {
      props: {
        isStatus: status,
      },
    };
  },
  { loadUser: true }
);
```

######3. condition where your query is meant to response only after logged in:######

here is the snippet for query where it gives response only for authenticated users example subscription query... you need to make small changes on above code. the status will return undefined if token(hasuraToken) will return nothing for non-authenticated user, so on that case you need to return null as shown below.

```
  const sub =
      token !== null &&
      (await client.query({
        query: PAYMENTS,
        context: {
          headers: {
            authorization: `Bearer ${token}`,
          },
        },
      }));

   const status = sub?.data;

   return {
      props: {
        isStatus: status === undefined ? null : status
      },
    };
    

```

For more info please refer to [Clerk](https://clerk.dev/docs/quickstarts/get-started-with-nextjs) and [Nextjs with SSR example](https://github.com/vercel/next.js/tree/canary/examples/with-apollo)

What do you think about this? Is there any other way that I haven't mentioned? Please please please let me know by commenting down below. I can't wait to hear that. Thanks

> Happy Coding!!