In Part 1 we learnt how to add users to a Airtable database with hashed passwords. In part 2 we are going to learn how to persist the user’s data with sessions.

Just want the code?

Get the full working demo on Github. If you want to follow along, download the starter files folder and rename it to whatever you would like and run yarn to install the dependencies. Don’t forget to check out part 1.

Configuring the session

We are going to use the express-session middleware, developed by the Express team to add simple sessions to express.

yarn add express-session

We then need to require the package in our app.js file and configure express to use the middleware. To learn more about using express-session please read the documentation on the Github repo.

// app.js
const session = require("express-session");

// session config
    secret: "arandomstring",
    resave: false,
    saveUninitialized: true

Protecting a route

Now that we have express-session included and configured, let’s protect our user profile route so logged out users cannot access the page. We are then going to create a session when a user is logged in, storing their user details in the session variable.

// index.js
router.get("/profile", userController.isLoggedIn, appController.getProfile);

Let’s now create our isLoggedIn function.

// userController.js
exports.isLoggedIn = (req, res, next) => {
  if (req.session && req.session.authenticated) {


This function is checking for the presence of a session. There will be a session if a user was successfully logged in. If there is no session, the user will be redirected to the login page.

Creating a session

Let’s edit our authenticate function in our userController.js to create the session.

// userController.js
exports.authenticate = (req, res, next) => {
  const { username, password } = req.body;
  const options = {
    filterByFormula: `OR(email = '${username}', username = '${username}')`

    .getAirtableRecords(table, options)
    .then(users => {
      users.forEach(function(user) {, user.get("password"), function(err, response) {
          if (response) {
            // Passwords match, response = true
            req.session.authenticated = user.fields;
          } else {
            // Passwords don't match
    .catch(err => {

Now when the usernames and passwords match (in the bcrypt callback function) we create a session passing the user data and redirect the user to their profile page. This will call the isLoggedIn function again which now passes the if condition, successfully logging the user in and redirecting them to their profile page with their data. Let’s update our getProfile function in our app controller to use the user data saved in our session.

// appController.js
exports.getProfile = (req, res) => {
  res.render("profile", {
    title: "Your Profile",
    user: req.session.authenticated

In the third and final part of this series, we will create a password reset workflow. Stay tuned.