Image for post
Image for post

Firebase: Introducing session cookies for server-side web apps

Web applications implemented using Firebase typically generate all the dynamic content at the client-side. The JavaScript code executes in the end-user’s web browser generating the output that the users see on screen. The same client-side code can also directly interact with Firebase services in the cloud such as Realtime Database and Storage. Other than the web server that serves up the static JavaScript and HTML files (which Firebase Hosting usually takes care of), no other application server or dynamic server-side web framework is required in this model.

But what if you are operating a more traditional website that generates content at the server-side, which you want to integrate with Firebase? Ideally you would want to authenticate users with Firebase Auth, and then direct them to a dynamic web page generated server-side. One way to achieve this is by getting hold of the ID token issued by Firebase Auth at sign-in, and then pass it to the back-end server with each request. The back-end server can verify the ID token using the Admin SDK, and generate the appropriate content. But as you can probably imagine, this is quite tedious to implement. You will end up having to inject the ID token into every single hyperlink and form post in the website.

Alternatively you can send the ID token with only the first request sent to the back-end server, where the server can verify, and set it as a cookie. Then you can rely on the browser to send the ID token with all subsequent requests. Cookies are widely used in dynamic server-side web applications, so this seems to fit right in. But the problem with this approach is that Firebase ID tokens are short-lived. They get cycled out once every hour, and dealing with frequent token changes can be both complicated and expensive.

Ideally, what you need is a credential that is:

  • long-lived (i.e. remains valid for few days),
  • verifiable at the server-side,
  • amenable to setting as a cookie, and
  • revokable if necessary.

Firebase now supports a concept called Firebase session cookies that meets all the above requirements. APIs for creating and verifying session cookies are gradually being introduced to Admin SDKs. At the time of this writing the new APIs for managing session cookies are available in Node.js and Python Admin SDKs, with the Java API awaiting review.

To incorporate Firebase session cookies into a website, a developer must implement the following server-side elements:

  1. A request handler that sets the Firebase session cookie on user sign-in. Lets call this the session initializer.
  2. Logic for verifying the Firebase session cookie on subsequent user requests.
  3. A request handler that clears the Firebase session cookie on user sign-out. Lets call this the session terminator.

When a user signs in, the web application must invoke the session initializer, passing it the ID token obtained from Firebase Auth. The session initializer uses the create_session_cookie() function of the Admin SDK to exchange the ID token for a Firebase session cookie. Developers can specify a validity period of up to 2 weeks when requesting the session cookie. The result of this operation is a signed JWT, which contains the same claims as the ID token. Session initializer then sets it as a cookie, so the browser will include it in subsequent requests to the same website. Listing 1 shows how to implement the session initializer in Python for a Flask web app. This examples produces cookies that are valid up to 5 days.

Other content-producing request handlers in the website may now inspect the Firebase session cookie, and verify it using the Admin SDK to authorize user requests. Listing 2 shows a Flask route that generates content for authenticated users. The verify_session_cookie() function raises an exception if the cookie fails to verify. Therefore users who hit this handler without a valid Firebase session cookie get redirected to the home page.

The cookie verification executes as a local operation in the Admin SDK most of the time. The SDK occasionally makes an HTTP call to fetch the Firebase public keys required to verify JWT signatures, but these get cached in memory — usually up to 24 hours. Therefore the cost of the network call gets amortized over many invocations. However, the verify_session_cookie() function accepts an optional check_revoked parameter. When set to True this checks whether the user’s login sessions have been revoked since the cookie was issued. This is usually the result of a large-scale change in the user account (e.g. password change), or a call to the revoke_refresh_tokens() function in the Admin SDK. This additional revocation check always incurs a network call.

Finally, when a user signs out, the web application must invoke the session terminator to clear out the Firebase session cookie. Listing 3 shows the corresponding Python code.

Firebase has always had excellent support for client-side app development, whereby most of the application logic is deployed and executed on end-user devices and web browsers. Admin SDKs and new features like session cookies make Firebase more accessible to conventional server-side app developers. If you’re a server-side web app developer, give the new session cookies support a try. Report any bugs or feature requests on opensource Firebase repos. Happy coding with Firebase!

Written by

Software engineer at Google. Enjoys working at the intersection of cloud, mobile and programming languages. Fan of all things tech and open source.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store