5

I am using a Apollo Client in ReactJS to communicate with GraphQL API. We use Firebase authentication and it's JWT to ensure our API don't expose private data the public but the problem is firebase token expires every one hour or so.

I am currently saving the IdToken localstorage when user login in and use that on the request headers but when token expires graphql returns Non Authorized error. I also tried using customfetch on createHttpLink function from the apollo

const customFetch = async (uri, options) => {
    console.log(firebase.auth.currentUser)
    if (firebase.auth.currentUser) {
        const token = await firebase.auth.currentUser.getIdToken()
        localStorage.setItem('token', token)
        options.headers.authorization = token;
        return fetch(uri, options);
    }
    else {
        firebase.auth.onAuthStateChanged(async (user) => {
            if (user) {
                console.log('Inside on Auth')
                const token = await user.getIdToken()
                localStorage.setItem('token', token)
                options.headers.authorization = token;
                return fetch(uri, options);
            }
        })
    }
    console.log('End of Fetch')
};

but fetch completes before firebase.auth.onAuthStateChanged is completed so it also don't work

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • I had a similar question, but am still having some other issues now: https://stackoverflow.com/questions/57163454/refreshing-a-token-with-apollo-client-firebase-auth – A.com Jul 25 '19 at 14:55

2 Answers2

8

Make it a custom link instead of a custom fetch.

import { ApolloClient } from 'apollo-client'
import { InMemoryCache } from 'apollo-cache-inmemory'
import { ApolloLink } from 'apollo-link'
import firebase from 'firebase/app'
import 'firebase/app'
import { setContext } from 'apollo-link-context'
const authLink = setContext((_, { headers }) => {
  //it will always get unexpired version of the token
  return firebase
    .auth()
    .currentUser.getIdToken()
    .then((token) => {
      return {
        headers: {
          ...headers,
          authorization: token ? `Bearer ${token}` : ''
        }
      }
    })
})
const link = ApolloLink.from([authLink, ...{/**ur other links */}])

const client = new ApolloClient({
  ssrMode: typeof window !== 'undefined',
  cache: new InMemoryCache().restore({}),
  link
})
  • Adding the docs from Apollo to make this answer more complete: https://www.apollographql.com/docs/react/networking/authentication/ – Siul Jan 03 '22 at 18:32
  • What should I do if I get `null` for `firebase.auth().currentUser`? Is there a way to do it with `onAuthStateChanged`, as explained here - https://medium.com/firebase-developers/why-is-my-currentuser-null-in-firebase-auth-4701791f74f0? – Nelu Mar 15 '22 at 13:30
-1

I use recursion for this, not sure is there any issue with it though.

firebase.auth.onAuthStateChanged(async (user) => {
    if (user) {
        setToken(user)
    }
})

const setToken = async (user) => {
    const token = await user.getIdToken();
    localStorage.setItem("token", token);

    setTimeout(() => setToken(user), 59000);
}