title: How to persist authentication in Next.js using firebase after token expiration and or refreshing the page
body: <p>I'm building an app with firebase and next.js. I'm having a hard time with firebase's authentication flows. Everything was coming along well until I noticed a bug/error. If I leave my computer logged in to the app for a while and whenever I refresh the page, It seems like both cause me to be redirected back to my login page. I can see why a refresh would trigger my redirect, as there may not be enough time for the onAuthStateChange to be checked in time for <code>const { user } = useAuth()</code> to run so since there is no user at initial page load (after refresh.) It will go in to the <code>{ else }</code> causing me to redirect at this point. But the funny thing is that if I simply click my dashboard (a protected page) link, I'm still authenticated. No redirections. Below is my code for my auth component:</p>
  <p>AuthComp.js:</p>
  <pre><code>import { useRouter } from &quot;next/router&quot;;
  import { useEffect, useState } from &quot;react&quot;;
  import { useAuth } from &quot;../../context/AuthContext&quot;;
  function LoadingScreen() {
      return &lt;div className=&quot;fixed top-0 right-0 h-screen w-screen z-50 flex justify-center items-center&quot;&gt;
          &lt;div className=&quot;animate-spin rounded-full h-32 w-32 border-t-2 border-b-2 border-gray-900&quot;&gt;&lt;/div&gt;
      &lt;/div&gt;
  }
  export function AuthComp(props) {
      const [isAuthenticated, setIsAuthenticated] = useState(false)
      const router = useRouter();
      const { user } = useAuth();
      useEffect(() =&gt; {
          let out;
          if (user) {
              setIsAuthenticated(true)
              return () =&gt; out ? out() : null
          } else {
              router.push('/auth')
          }
          return () =&gt; out;
      }, [user])
      if (!user &amp;&amp; (!isAuthenticated)) {
          return &lt;LoadingScreen /&gt;;
      }
      return &lt;props.Component user={user} /&gt;
  };
  </code></pre>
  <p>Here is my code for my auth context file: AuthContext.js:</p>
  <pre><code>import React, { useState, useEffect, createContext, useContext } from 'react'
  import { fbase } from '../utils/auth/firebaseClient'
  
  export const AuthContext = createContext()
  
  export default function AuthProvider({ children }) {
      const [user, setUser] = useState(null)
      const [loadingUser, setLoadingUser] = useState(true) // Helpful, to update the UI accordingly.
  
      useEffect(() =&gt; {
          // Listen authenticated user
          const unsubscriber = fbase.auth.onAuthStateChanged(async (user) =&gt; {
              try {
                  if (user) {
                      setUser(user);
                  } else {
                      setUser(null)
                      return;
  
                  }
              } catch (error) {
                  // Most probably a connection error. Handle appropriately.
                  console.log('an error occurred', error);
              } finally {
                  setLoadingUser(false)
              }
          })
  
          // Unsubscribe auth listener on unmount
          return () =&gt; unsubscriber()
      }, [])
  
      return (
          &lt;AuthContext.Provider value={{ user, setUser, loadingUser }}&gt;
              {children}
          &lt;/AuthContext.Provider&gt;
      )
  }
  
  // Custom hook that shorthands the context!
  export const useAuth = () =&gt; useContext(AuthContext)
  </code></pre>