Firebase: Introducing session cookies for server-side web apps
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:
- A request handler that sets the Firebase session cookie on user sign-in. Lets call this the session initializer.
- Logic for verifying the Firebase session cookie on subsequent user requests.
- 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!