Backend-Only Authentication With Sapper & Firebase Admin
In my last story, I described how to implement an authentication system with Sapper and Firebase Auth on the client-side. An alternative way is to use server-side sessions with the help of Firebase Admin and the Firebase REST API. Before I show you some code, a little background story about the idea behind this authentication flow.
0. Overview & explanation
Developing an authentication system with Firebase can be done in two ways: handling the session client-side or make it use your own session-based back-end. Some advantages of using Back-End only are:
- No front-end bloat (saving precious KB's…)
- Secure (when done right). The user won't have to interact with his Firebase-uid. Everything can be done via the shared store from Sapper.
- This also circumvents the 1-hour session problem. Setting your own time-limit for your sessions (up to two weeks) via Firebase Admin.
This setup works nicely together with Sapper. I drew a beautiful picture of the overview of the architecture, with a step-by-step explanation below.
Imagine we have an application with a protected route, and the user logs in with their credentials.
- Our Sapper API-route will fetch the user from the Firebase REST-point and creates a session token with Firebase Admin. This token can be valid for up to two weeks.
- If successful, we populate our Sapper Session store via the middleware and save our user-info in it.
- Our store is shared with the client-side and the user will be able to perform authenticated actions.
- When a user returns to our application, the session token (saved as a cookie) will recognize our user and logs in automatically.
1. Setup a new project with protected routes
We start with a fresh Sapper-project named 'firebase-backend', install all the dependencies and then remove the entire blog-folder in /src/routes and the about.svelte page since we won't be needing those. Create two new blank pages named dashboard.svelte and a login.svelte.
npx degit "sveltejs/sapper-template#rollup" firebase-backend
Go to the Nav-component inside /src/components/ and add the new pages to it.
2. Secure the dashboard page
If you run yarn dev and navigate to http://localhost:3000.You should be able to freely navigate between all the (empty) pages.
Let’s protect our dashboard.svelte for unauthorized access. Firstly, we use the sapper.middleware() to populate our Sapper store/session when a user connects to the server. This needs to be done in server.js. Add a user; its default value will be false. I use express btw, instead of polka.
Now we check in our dashboard.svelte if a user exists, otherwise we redirect to the login page.
3. Log in as a user
Our dashboard page is now protected and will just redirect to the login page (since our user in our session is always false). We need to log in as a user and, as explained in chapter 0, we will do this in the back-end via API calls.
Firstly, we want to send an API-call with our credentials to the server via our login-page.
The API-call to /session does not exist yet. Before we create this API-route, we need some packages installed: Firebase Admin, node-fetch (to perform fetch actions on our back-end), body-parser, cookie-parser.
yarn add firebase-admin node-fetch body-parser cookie-parser
After installing these packages, create a file called firebaseAdmin.js in /src/-folder (which will have all your Firebase Admin config values). It should look something like this:
Now we are set-up for our session-call. Create a new file called session.js inside /src/routes/-folder. This API-route checks the credentials sent from the client and tries to get an idToken via a call to the Firebase REST endpoint. Then it creates a session-cookie named fireCookie.
Our API-route is set, but if you try to make a call to it, an error shows that req.body is undefined. We need to adjust server.js by adding the cookieParser and use the body-parser to read JSON to our express server. Let's also adjust the Sapper middleware to set the user in our session when the fireCookie is found.
Now when a new user with a legit cookie connects, the session store of Sapper gets filled and the user can visit the dashboard page.
4. Loggin out
A user also needs to be able to logout. Simply create a logout-button in your dashboard.svelte, which calls a (soon to be created) API-route to sessionLogout.
Create a new API-route called sessionLogout.js inside your /routes/-folder and logout the session via the official Firebase Documentation methods.
Summary
So that's it. A simple way of managing user state, purely on the back-end and which shares its state via the Sapper Session Store. Since I wanted to keep this tutorial as simple as possible, I didn't focus too much on security. You might want to perform some extra's value-checks and implement a CSFR-token for sensitive-actions. Let me know what you think, or if things are missing!