title: How to Refresh Firebase Session Cookie
body: <p>I'm developing a web application using Node.js/Express.js for the backend and I use Firebase for user authentication, and to manage user registration etc I use Firebase Admin SDK.</p>
  
  <p>When a user want to login I sign him in using Firebase Client SDK like this:</p>
  
  <pre><code>// Handling User SignIn
  $('#signin').on('click', function(e){
      e.preventDefault();
  
      let form = $('#signin-form'),
          email = form.find('#email').val(),
          pass = form.find('#password').val(),
          errorWrapper = form.find('.error-wrapper');
  
      if(email &amp;&amp; pass){
          firebase.auth().signInWithEmailAndPassword(email, pass)
              .catch(err =&gt; {
                  showError(errorWrapper, err.code)
              });
      }else {
          showError(errorWrapper, 'auth/required');
      }
  });
  </code></pre>
  
  <p>Below this code, I set an observer to watch for when the user successfully sign in, After a successfull sign in I get a Firebase ID token which I send to an endpoint on the server to exchange it for a session cookie that has the same claims the ID token since the later expires after 1 hour.</p>
  
  <pre><code>// POST to session login endpoint.
  let postIdTokenToSessionLogin = function(url, idToken, csrfToken) {
      return $.ajax({
          type: 'POST',
          url: url,
          data: {
              idToken: idToken,
              csrfToken: csrfToken
          },
          contentType: 'application/x-www-form-urlencoded'
      });
  };
  
  // Handling SignedIn Users 
  firebase.auth().onAuthStateChanged(function(user) {
      if (user) {
          user.getIdToken().then(function(idToken) {
              let csrfToken = getCookie('csrfToken');
              return postIdTokenToSessionLogin('/auth/signin', idToken, csrfToken)
                  .then(() =&gt; {
                          location.href = '/dashboard';
                      }).catch(err =&gt; {
                          location.href = '/signin';
                      });
                  });
          });
      } else {
          // No user is signed in.
      }
  });
  </code></pre>
  
  <p>Sign in endpoint on the server looks like this:</p>
  
  <pre><code>// Session signin endpoint.
  router.post('/auth/signin', (req, res) =&gt; {
      // Omitted Code...
      firebase.auth().verifyIdToken(idToken).then(decodedClaims =&gt; {
          return firebase.auth().createSessionCookie(idToken, {
              expiresIn
          });
      }).then(sessionCookie =&gt; {
          // Omitted Code...
          res.cookie('session', sessionCookie, options);
          res.end(JSON.stringify({
              status: 'success'
          }));
      }).catch(err =&gt; {
          res.status(401).send('UNAUTHORIZED REQUEST!');
      });
  });
  </code></pre>
  
  <p>I have created a middle ware to verify user session cookie before giving him access to protected content that looks like this:</p>
  
  <pre><code>function isAuthenticated(auth) {
      return (req, res, next) =&gt; {
          let sessionCookie = req.cookies.session || '';
          firebase.auth().verifySessionCookie(sessionCookie, true).then(decodedClaims =&gt; {
              if (auth) {
                  return res.redirect('/dashboard')
              } else {
                  res.locals.user = decodedClaims;
                  next();
              }
          }).catch(err =&gt; {
              if (auth) next();
              else return res.redirect('/signin')
          });
      }
  }
  </code></pre>
  
  <p>To show user information on the view I set the decoded claims on <code>res.locals.user</code> variable and pass it to the next middle ware where I render the view and passing that variable like this.</p>
  
  <pre><code>router.get('/', (req, res) =&gt; {
      res.render('dashboard/settings', {
          user: res.locals.user
      });
  });
  </code></pre>
  
  <p>So far everything is fine, now the problem comes after the user go to his dashboard to change his information (name and email), when he submits the form that has his name and email to an endpoint on the server I update his credentials using Firebase Admin SDK</p>
  
  <pre><code>// Handling User Profile Update
  function settingsRouter(req, res) {
      // Validate User Information ...
      // Update User Info
      let displayName = req.body.fullName,
          email = req.body.email
      let userRecord = {
          email,
          displayName
      }
      return updateUser(res.locals.user.sub, userRecord).then(userRecord =&gt; {
          res.locals.user = userRecord;
          return res.render('dashboard/settings', {
              user: res.locals.user
          });
      }).catch(err =&gt; {
          return res.status(422).render('dashboard/settings', {
              user: res.locals.user
          });
      });
  }
  </code></pre>
  
  <p>Now the view gets updated when the user submits the form because I set the <code>res.locals.user</code> variable to the new <code>userRecord</code> but once he refreshes the page the view shows the old credentials because before any get request for a protected content the middle ware <code>isAuthenticated</code> gets executed and the later gets user information from the session cookie which contains the old user credentials before he updated them.</p>
  
  <p>So far these are the conclusions that I came to and what I tried to do:</p>
  
  <ul>
  <li><p>If I want the view to render properly I should sign out and sign in again to get a new Firebase ID token to create a new session cookie which is not an option.</p></li>
  <li><p>I tried to refresh the session cookie by creating a new ID token from the Admin SDK but it doesn't seem to have this option available and I can't do that through the client SDK because the user is already signed in.</p></li>
  <li><p>Storing the ID token to use later in creating session cookies is not an option as they expire after 1 hour.</p></li>
  </ul>
  
  <p>I Googled the hell out of this problem before posting here so any help is so much appreciated.</p>