Add Context Link to Apollo Link after Client is created (after log-in)
Asked Answered
L

2

5

I want to add a Context Link to an existing client's Apollo Link chain.

Here are two GitHub issues I've read through: First, Second.

I do not want to use local storage to store the token as the docs show here.

I have an auth provider which stores my token. After storing my token I'd like to add a Context Link to the Apollo Client's links

  const authLink = setContext((_, { headers }) => {
    const newHeaders = { ...headers };
    if (token) newHeaders.authorization = `Bearer ${token}`;

    return {
      headers: newHeaders,
    };
  });

I know I can access the client via useClient. How do I append this link to the client's already existing from my component without doing it before making the client?

link: authLink.concat(httpLink) or link: authLink.concat(whateverLinksApolloHas)

Lightness answered 1/4, 2020 at 15:20 Comment(0)
T
1

I don't believe there's a supported way of doing what you're trying to do. What you can do is initialize a new instance of ApolloClient and pass that to ApolloProvider instead. For example:

const [token, setToken] = useState(null)
const client = getClient(token) // adds the appropriate links as necessary

return <ApolloProvider client={client}><App/></ApolloProvider>

If you go this route and need to keep your cache when the token changes, make sure you utilize the same instance of InMemoryCache each time you create the client.

However, even this is probably overkill. There's no reason you can't always use setContext. You're already checking whether token exists before modifying the headers.

Taco answered 2/4, 2020 at 11:7 Comment(2)
Agreed it's overkill. Now I'm trying to figure out how to access a context each time a request is made in my AuthLink. Replacing local storage with a context value with hooks.Lightness
I'm using localStorage because I'll need to store there eventually anyways to persist user log-in. Thanks for the help.Lightness
L
11

As of Apollo Client v3.0.0, you can now update the link chain using the setLink method on an Apollo Client after it has been created (see Changelog Section v3).

Apollo Client now supports setting a new ApolloLink (or link chain) after new ApolloClient() has been called, using the ApolloClient#setLink method. @hwillson in #6193

However, I have not found any documentation about it other than this though.

I wasn't able to just add a context link using setContext. Instead, it looks like it replaces the entire link chain, so here was my solution using @apollo/[email protected].

import { ApolloClient, HttpLink, NormalizedCacheObject } from '@apollo/client/core';
import { setContext } from '@apollo/client/link/context';
import fetchNewToken from 'your-token-function-file'

const replaceLinkChainOnClient = (client: ApolloClient<NormalizedCacheObject>, url: string) => {
    const httpLink: HttpLink = new HttpLink({
        uri: url
    });

    const link = setContext(async (operation, prevContext) => {
        const token = await fetchNewToken();
        return {
            ...prevContext,
            headers: {
                ...prevContext.headers,
                Authorization: `Bearer ${token}`
            }
        };
    });
    client.setLink(link.concat(httpLink));
};

Lutenist answered 28/10, 2020 at 23:3 Comment(0)
T
1

I don't believe there's a supported way of doing what you're trying to do. What you can do is initialize a new instance of ApolloClient and pass that to ApolloProvider instead. For example:

const [token, setToken] = useState(null)
const client = getClient(token) // adds the appropriate links as necessary

return <ApolloProvider client={client}><App/></ApolloProvider>

If you go this route and need to keep your cache when the token changes, make sure you utilize the same instance of InMemoryCache each time you create the client.

However, even this is probably overkill. There's no reason you can't always use setContext. You're already checking whether token exists before modifying the headers.

Taco answered 2/4, 2020 at 11:7 Comment(2)
Agreed it's overkill. Now I'm trying to figure out how to access a context each time a request is made in my AuthLink. Replacing local storage with a context value with hooks.Lightness
I'm using localStorage because I'll need to store there eventually anyways to persist user log-in. Thanks for the help.Lightness

© 2022 - 2024 — McMap. All rights reserved.