DEV Community

Cover image for Using Apollo GraphQL and SSR
Samuel Joseph Thompson
Samuel Joseph Thompson

Posted on

Using Apollo GraphQL and SSR

This is a short post about how to add a JWT Authentication flow to a golang backend with a Next.js (typescript) front end that utilizes Server Side Rendering (SSR).
While utilizing Next Auth for single sign on authentication flow for the front end to ease the user's experience, I found myself in a pickle due to not being able to pass headers to my JWT authentication flow on a backend hosted on golang with graphql.
Part of the issue arises when using SSR as one cannot simply pass the JWT via a request header by accessing session (or local) storage in the browser. Thus via a bit of creativity, and scouring other examples online I came up with an adjustment to exporting an apollo client.
At first I attempted to create an apollo client via the below code and accessing the JWT token from useSession, sessionStorage, localStorage, etc.

import { ApolloClient, createHttpLink, InMemoryCache } from "@apollo/client";
 const authLink = setContext(async (_, { headers }) => {
        return {
            headers: {
                ...headers,
                Authorization: context ? context : "",
            }
        }
    });

const client = new ApolloClient({
        link: authLink.concat(httpLink),
        ssrMode: typeof window === 'undefined',
        cache: new InMemoryCache()
    });
}

export default client;
Enter fullscreen mode Exit fullscreen mode

I found I was still unable to access any sort of context associated with the application, without running into callback issues. Thus with the client created and returned asynchronously below:

import { ApolloClient, createHttpLink, InMemoryCache } from "@apollo/client";
import { setContext } from "@apollo/client/link/context";

const httpLink = createHttpLink({
    uri: process.env.GRAPHQL_URI,
    credentials: "include"
})
const createClient = async (context: any) => {
    console.log('client context', context)
    const authLink = setContext(async (_, { headers }) => {
        return {
            headers: {
                ...headers,
                Authorization: context ? context : "",
            }
        }
    });
    return new ApolloClient({
        link: authLink.concat(httpLink),
        ssrMode: typeof window === 'undefined',
        cache: new InMemoryCache()
    });
}

export default createClient;
Enter fullscreen mode Exit fullscreen mode

We're now able to access the session data in an SSR call by passing the session data (via setting a JWT cookie parameter) like below:

 const client = await createClient(sessionData?.Authorization);
Enter fullscreen mode Exit fullscreen mode

After which point we can now pass our JWT similar to how we would using the client side session storage or local storage.
Hopefully this helps out fellow peeps who want a separation of concerns with respect to backend /frontend apis and maintain their own authentication flows.

Oldest comments (0)