Logo

dev-resources.site

for different kinds of informations.

SSR: clerk with hasura

Published at
7/21/2022
Categories
clerk
hasura
graphql
nextjs
Author
smileyshivam
Categories
4 categories in total
clerk
open
hasura
open
graphql
open
nextjs
open
Author
12 person written this
smileyshivam
open
SSR: clerk with hasura

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

Clerk
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]
  );
}
Enter fullscreen mode Exit fullscreen mode
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 }
);
Enter fullscreen mode Exit fullscreen mode
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
      },
    };


Enter fullscreen mode Exit fullscreen mode

For more info please refer to Clerk and Nextjs with SSR example

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!!

hasura Article's
30 articles in total
Favicon
Convert insert mutation to upsert
Favicon
refinedev - hasura (nested/multiple query_root)
Favicon
From Idea to Launch: My 30-Day MVP Journey
Favicon
How to Build a GraphQL API for MongoDB Using Hasura in Six Steps
Favicon
How to Build a Supergraph using Snowflake, Neon PostgreSQL, and Hasura in Five Steps
Favicon
Streamlining CI/CD Pipelines with Hasura GraphQL Engine
Favicon
Supabase over Hasura for 2024?
Favicon
Hasura and Keycloak integration with NestJS server
Favicon
Modern API Development (Part 1)
Favicon
Build a graphQL API with Hasura low-code platform
Favicon
Startup Starter Kit
Favicon
Hasura x MEWS
Favicon
Hasura vs Apollo: Comparing GraphQL Platforms
Favicon
Hasura and Nhost vs Supabase
Favicon
How to monitor URQL performance and link with database queries ?
Favicon
Build a Powerful GraphQL API with Postgres in Under 10 Minutes
Favicon
Guide to Side effects in Hasura
Favicon
Hasura: Building Scalable and Real-Time Applications - An Extensive Guide
Favicon
Hasura Cloud: Building Scalable and Secure GraphQL APIs Made Easy
Favicon
How to avoid messing up squash migration in Hasura
Favicon
Appwrite vs. Hasura vs. Apollo
Favicon
Auth0, Hasura, Social Media Login
Favicon
Deno & Hasura for app development
Favicon
SSR: clerk with hasura
Favicon
Hasura Custom Authentication Using JWT
Favicon
Unable to HASURA_GRAPHQL_JWT_SECRET in docker-compose file
Favicon
Hasura Storage in Go: 5x performance increase and 40% less RAM
Favicon
Using Authorizer with Hasura
Favicon
Hasura + Supertokens
Favicon
Creating a todo web app in < 112 lines of code with Hasura and Python

Featured ones: