skip to Main Content

I’ve got a React app using socket.io and firebase auth. The socket connections are authenticated based on an authtoken set in a cookie which i get from firebase’s getIdToken method.

Normally I have this tokenRefreshingFn that refreshes the token every 25 minutes while they’re using the app because firebase id tokens (authtoken, whatever) expire every hour.

But I realized that when the user closes their laptop for awhile and comes back, when they go back to the page the authtoken will have expired since the token refreshing interval fn won’t have been executing and firebase authtokens only last 1 hour. So the socket.io server would start treating them as logged out even though they’re logged in, because the token expired while their laptop was closed.

To rectify this, i added the following useEffect to the top level of the app:

useEffect(() => {
  document.addEventListener('visibilitychange', () => {
      appStore.update(s => {
        clearInterval(s.tokenRefreshingFn);

        if (auth.currentUser) {
          s.tokenRefreshingFn = setInterval(async () => {
            const newAuthToken = await auth.currentUser!.getIdToken(true);
            Cookies.set('authToken', newAuthToken);
          }, ONE_MINUTE * 25);
        } else {
          s.signedIn = false;
          s.tokenRefreshingFn = null;
        }
      });
    });
  }, []);

Is this valid? do you see any problems with this?

2

Answers


  1. The Firebase SDKs take this approach to refreshing tokens and being offline:

    • The Firebase Authentication SDK refreshes the ID token about 5 minutes before it expires.
    • When a Firebase SDK that supports authentication (e.g. the Realtime Database) detects that it is reconnected to the server but that its ID token is now expired, it first refreshes the ID token and only then sends any operations to the database server (e.g. pending writes and reattaching listeners).

    I’d try to follow the same approach in your own code, so you may want to consider if your use-case really needs a 25 minutes interval for this.

    Login or Signup to reply.
  2. You are using socket.io, then using connect_error is the way to go.

    useEffect(() => {
        socket.on("connect_error", (err) => {
          if (err.message == "not authorized") {
            // call connect function again
          }
        });
    
    }, [])
    

    In your connect function, it should get the new token every time it’s called.

    In most cases, the following is not necessary, since reconnection with new token is handled by your connect function.

    Normally I have this tokenRefreshingFn that refreshes the token every
    25 minutes while they’re using the app because firebase id tokens
    (authtoken, whatever) expire every hour.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search