'Firebase JWT token expires in 60 minutes

In Reactjs application I am working on authorization system. Everything is working fine but problem is the authorization lasts for 60 minutes only. After I need to login again as the token is not valid any more. I use the token to authorize GraphQL data queries. This is the hook (removed some parts of code as Stack Overflow requires for the questions to contain sertain proportions of code to description)

firebase.initializeApp({ firebase data});
const fbAuth = getAuth();
const authContext = createContext();


export function ProvideAuth({ children }) {
  const auth = useProvideAuth();
  return <authContext.Provider value={auth}>{children}</authContext.Provider>;
}

export const useAuth = () => {
  return useContext(authContext);
};


function useProvideAuth() {
  const guestUser = { email: "", role: "guest", token: "" };

  const [user, setUser] = useState(guestUser);
  const [token, setToken] = useLocalStorage("token", "");

  const signin = (email, password) => {
    return setPersistence(fbAuth, browserLocalPersistence)
      .then(() => {
        return signInWithEmailAndPassword(fbAuth, email, password)
          .then((userCredential) => {
            // Signed in
            const user = userCredential.user;
            console.log("user po zalogowaniu", user);

            return true;
          })
          .catch((error) => {..});
      })
      .catch((error) => {...});
  };

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(fbAuth, (user) => {
      if (user) {
        const uid = user.uid;
        const decoded = decodeToken(user.accessToken);
       
        setUser((u) => ({
          email: user.email,
          role: decoded.role,
          token: user.accessToken,
        }));
          setToken(user.accessToken);
                
      } else {
        // User is signed out
        console.log("user signed out");
       }
    });

    // Cleanup subscription on unmount
    return () => unsubscribe();
  }, []);

  // Return the user object and auth methods
  return {
    user,
    token,
    signin,
    signout,
    sendPasswordResetEmail,
    confirmPasswordReset,
    
  };
}

I am using the singin method to sign in and obtain JWT token but the problem is I have to re-login every 60 minutes to get valid token (which I use in API queries). Not sure how Firebase subscriptions are supposed to work. I do not understand how to make it auto-refresh. Now I need to reload the page to get valid token... I would appreciate any help.

EDIT Following Frank's hint I added another useEffect to the hook:

 useEffect(() => {
    const unsubscribe = onIdTokenChanged(fbAuth, (user) => {
      if (user) {
        const uid = user.uid;
        const decoded = decodeToken(user.accessToken);
        setUser((u) => ({
          email: user.email,
          role: decoded.role,
          token: user.accessToken,
        }));
        setToken(user.accessToken);
      } else {
        console.log("user signed out");
      }
    });
    return () => unsubscribe();
  }, []);

...but nothing changed, still need to re-login to get new token.



Solution 1:[1]

Firebase uses a combination of long-lived and short-lived tokens to maintain the user's authentication state. While the ID token is only valid for an hour, the Firebase SDK automatically refreshes it behind the scenes before it expires.

If you want to get notified of updates to the user's ID token, you can listen to the onIdTokenChanged events and use those to update the ID token in your state.

Solution 2:[2]

Could not get it to work. The problem may be related to the fact that I am using firebase only for autorization and getting the token... not sure.

Anyway I have made refresh function:

function refresh() {
    if (fbAuth.currentUser) {
      fbAuth.currentUser.getIdToken(true).then((token) => {
        console.log(token);
        // setCurrentUser((user) => ({ ...user, accessToken: token }));
        setToken({ value: token });
      });
    }
  }

which I am using to get new token every 40 minutes:

  useEffect(() => {
    const tokenRefreshInterval = setInterval(() => {
      refresh();
      console.log("REFRESHING TOKEN");
    }, 40 * 60 * 1000);
    return () => clearInterval(tokenRefreshInterval);
  }, []);

Not a big fan of the solution but it is all I get for now...

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Frank van Puffelen
Solution 2 oskar333