LogoLogo
  • FAC Curriculum
  • archive
    • Node & npm introduction
    • developer
      • Programming Paradigms
    • handbook
      • Asking for help
      • Coaching groups
      • Code review
      • Course rules
      • Debugging
      • Employment schedule and material delivered in FAC20
      • GitHub Workflow
      • Glossary or terms
      • Presentation Guidance
      • Equality, Diversity and Inclusion
      • Installation guide
      • Learning circles
      • Mentoring guidance
      • What to expect from your mentors
      • One-day projects
      • Pair programming
      • Portfolio
      • Questions for problem solving
      • Progress Logs
      • Final project report
      • Managing software projects
      • Project Presentations
      • Project roles
      • Projects
      • Retrospectives
      • Role Circles
      • Safeguarding policy
      • Technical Spikes
      • System requirements
      • Tech for Better
      • User Manuals
      • Wellbeing Support
      • project-docs
        • What makes a mentor?
        • Product Handover
        • Sprint Planning
        • Tech for Better Presentations
        • User Research & Usability Testing
    • foundation
      • full-stack
        • Learning Outcomes
        • project
      • testing
        • project
        • spikes
  • docs
    • Contributing to the curriculum
    • Curriculum intent
    • Curriculum process
  • src
    • About our curriculum
    • course
      • Code of Conduct
      • Docker
      • .NET and Umbraco
      • Getting started
      • Founders and Coders coursebook
      • KSB's
      • Mini projects
      • Revision checklist
      • Svelte
      • TypeScript
      • handbook
        • Software Developer Handbook
        • Software Foundation Handbook
      • precourse
        • Before you start the course
        • Installation List
      • syllabus
        • developer
          • app
            • learning-outcomes
            • project
            • schedule
            • spikes
          • introduction
            • learning-outcomes
            • project
            • resources
            • schedule
          • week00-pre-course
            • We'd like you to spend some time before starting the course working on useful fundamentals.
            • spikes
          • week01-project01-basics
            • Employability introduction
            • Homework
            • learning-outcomes
            • Week of September 9th
            • project
            • resources
            • schedule
            • spikes
          • week02-project02-chatbot
            • employability
            • Homework
            • learning-outcomes
            • Week of September 16th
            • project
            • resources
            • schedule
            • spikes
          • week03-project03-server
            • Learning Outcomes
            • Week of September 23th
            • The Amazin' Quizzer API Backend
            • resources
            • schedule
          • week04-project03-frontend
            • learning-outcomes
            • Week of September 30th
            • UI for Quizzer App
            • resources
            • schedule
          • week05-project03-test-deploy
            • Testing and deployment
            • Week of October 7th
            • project
            • resources
            • schedule
          • week06-project04-databases
            • learning-outcomes
            • Week of October 14th
            • project
            • Databases
            • schedule
          • week07-project04-authentication
            • Learning Outcomes
            • Week of October 21st
            • project
            • resources
            • schedule
          • week08-project04-test-deploy
            • Learning Outcomes
            • Week of October 28th
            • project
            • resources
            • schedule
          • week09-reading-week
            • Learning Outcomes
            • overview
            • Project
            • Resources
            • schedule
          • week10-project05-DOTNET-intro
            • Learning Outcomes
            • overview
            • project
            • Resources
            • schedule
          • week11-project05-DOTNET-testing
            • Testing and deployment
            • Week of November 18th
            • project
            • Resources
            • schedule
          • week12-project05-DOTNET-deploy
            • Learning Outcomes
            • Week of November 25th
            • project
            • Resources
            • schedule
            • Spikes
          • week13-TFB-design
            • Learning Outcomes
            • overview
            • Project
            • Resources
            • schedule
            • Design Week Spikes
          • week14-TFB-build
            • Learning Outcomes
            • overview
            • Project
            • DevOps Resources
            • schedule
            • Spikes
          • week15-TFB-build
            • Learning Outcomes
            • overview
            • Project
            • Resources
            • schedule
            • Spikes
          • projects
            • in-house-design
              • Learning Outcomes
              • Project
              • Resources
              • schedule
              • Design Week Spikes
        • foundation
          • Obsolete-full-stack
            • project
          • post-course
            • Homework
            • schedule
        • portfolio
          • fruit-shop
            • learning-outcomes
            • project
            • resources
          • game
            • learning-outcomes
            • project
            • resources
          • hobby-page
            • learning-outcomes
            • project
            • resources
          • movie-data
            • learning-outcomes
            • project
            • resources
          • project-gallery
            • learning-outcomes
            • project
            • resources
          • website
            • learning-outcomes
            • project
            • JavaScript
        • tfb
          • week 1
            • Introduction (45 minutes)
            • Further reading
          • week 10
            • content
            • resources
          • week 11
            • What will we be doing this week?
            • resources
          • week 12
            • What will we be doing this week?
            • Further reading
          • week 2
            • Discover (90 minutes)
            • resources
          • week 3
            • content
            • resources
          • week 4
            • Mapping the user journey (90 minutes)
            • resources
          • week 5
            • Figma Workshop 1 (90 minutes)
            • Further reading
          • week 6
            • Figma Workshop 2 (90 minutes)
            • resources
          • week 7
            • Product pitches & Selection (90 minutes)
            • resources
          • week 8
            • content
            • resources
          • week 9
            • content
            • resources
    • learn
      • DOTNET
        • Introduction to .NET
      • auth
        • Authenticating web apps
      • database
        • Persisting data with SQLite and Node
      • dotnet-two
        • Dependency injections and interfaces in .NET
      • form-validation
        • Form validation
      • react
        • Building client-side apps with React
      • server
        • HTTP servers with Node & Express
      • typescript
        • TypeScript
    • mentoring
      • design-week
        • Analysis Workshop
        • Code planning
        • Definition Workshop
        • Discovery Workshop
        • Figma introduction
        • Usability testing
        • User Research
    • resources
      • http
        • introduction
    • workshops
      • cookie-auth
        • index
      • creating-promises
        • index
      • css-layout
        • index
      • cypress-testing
        • index
      • database-testing
        • index
      • dev-tooling
        • Developer tooling
      • dom-challenge
        • index
      • dom-rendering
        • index
      • es-modules
        • index
      • express-middleware
        • Express middleware
      • first-class-functions
        • index
      • form-validation
        • index
      • functions-callbacks-async
        • Functions, callbacks, & async JavaScript
      • git-intro
        • Introduction to Git
      • git-terminal
        • Using Git in the terminal
      • git-workflow
        • Git workflow
      • github-projects
        • GitHub Projects Workflow Workshop
      • heroku-sql-challenge
        • index
      • html-forms
        • index
      • learn-a11y
        • index
        • starter-files
          • solution
            • Accessibility solution explanation
      • learn-fetch
        • index
      • learn-integration-testing
        • index
      • learn-testing
        • Learn testing in JavaScript
      • learn-unit-testing
        • index
      • node-error-handling
        • Node error-handling
      • node-express-server
        • Node and Express HTTP server
      • node-npm-intro
        • Node & npm introduction
      • node-postgres
        • Learn Postgres with Node
      • node-scripting-challenge
        • index
      • password-security
        • index
      • promise-practice
        • index
      • react-components
        • React components
      • react-fetch
        • index
      • react-forms
        • React forms
      • react-refactor-classes
        • index
      • react-state-effects
        • React state & effects
      • real-world-fetch
        • index
      • scope-challenge
        • Scope debugging challenge
      • semantic-html
        • index
      • server-side-forms
        • Server-side forms
      • session-auth
        • Session authentication
      • sql-intro
        • index
      • tdd-array-methods
        • index
Powered by GitBook
On this page
  • Setup
  • Code overview
  • Part one: storing sessions in the DB
  • Part two: signing up
  • Part three: logging in
  • Stretch goal: logging out
Export as PDF
  1. src
  2. workshops
  3. session-auth

Session authentication

Learn how to log users in using session cookies

This workshop will show you how to combine password-based authentication with cookie-based sessions to keep users logged in to your site.

Setup

  1. Download the starter files and cd in

  2. Run npm install

Database setup

The starter files include two scripts to help with database setup.

Create a new Postgres user and database using:

./scripts/create_db

This script will also create a .env file containing the DATABASE_URL environment variable, so your server knows how to connect to the local DB.

Insert example data into the database using:

./scripts/populate_db

This will recreate all the tables from scratch each time you run it, so it can be handy to "reset" everything if you mess up during the workshop.

Finally you can start the server:

npm run dev

Code overview

Take a moment to look at the existing code. The server has routes for signing up and logging in. The GET routes render forms, but the POST routes don't do anything but redirect.

Important: a COOKIE_SECRET environnment variable is set in the .env file and used to configure the cookie-parser middleware. When you deploy a server to Heroku you'll need to create a long random string and set it in your app's "Config vars" in Settings.

The database created in database/init.sql contains two tables: users and sessions. We'll be storing new users who sign up in users, and currently logged in users in sessions.

The sessions table has a data column that is the JSON type. This means it can store generic blobs of unstructured data, which is perfect for a session since we don't know exactly what we want to put in there in advance.

You're going to implement the sessions-based authentication functionality. You'll work step-by-step to create each part of the code as a separate function, then bring all the parts together to make the server work.

There are unit tests for each part of the workshop. You can run these to find out if you've implemented the functions correctly. For example:

npm run test:one

Part one: storing sessions in the DB

The database-related code is separate from the rest of the server logic, in database/model.js. There are already some functions for accessing data in this file.

The model is missing a way to insert new sessions into the database, so you need to write this function.

  1. Write a createSession function that takes a session ID and a data object, inserts them into the sessions table, and returns the session ID. For example:

    model
      .createSession("def456", { just: "testing things" })
      .then((sid) => console.log(sid));
    // Logs: "def456"
function createSession(sid, data) {
  const INSERT_SESSION = `
    INSERT INTO sessions (sid, data) VALUES ($1, $2)
    RETURNING sid
  `;
  return db
    .query(INSERT_SESSION, [sid, data])
    .then((result) => result.rows[0].sid);
}

Part two: signing up

User sign up is a three-step process:

  1. Get the submitted user data, hash the password, insert the user into the DB

  2. Create a new session ID, then store the user data in the sessions table (so they're logged in)

  3. Set a cookie containing the session ID so they stay logged in on future requests

The auth.js file is going to contain all the authentication related code. You'll need to write two functions in here, one to create a user and one to save a session.

  1. Write a createUser function in auth.js. It should take an email, password, and name as arguments, hash the password, then store the user in the database, returning the saved user. For example:

    auth
      .createUser("oli@o.com", "hunter2", "Oli")
      .then((user) => console.log(user));
    // Logs: { email: "oli@o.com", name: "Oli" }
  2. Write a saveUserSession function in auth.js. It should take a user object, generate a random session ID, then store the user data in the sessions table. For example:

    auth
      .saveUserSession({ email: "oli@o.com", name: "Oli" })
      .then((sid) => console.log(sid));
    // Logs: "ljasf7y983wrkbdss="

Hint: you can generate a random, long session ID using Node's crypto module:

crypto.randomBytes(18).toString("base64");
function createUser(email, password, name) {
  return bcrypt
    .hash(password, 10)
    .then((hash) => model.createUser(email, hash, name));
}

function saveUserSession(user) {
  const sid = crypto.randomBytes(18).toString("base64");
  return model.createSession(sid, { user });
}

module.exports = { createUser, saveUserSession, COOKIE_OPTIONS };

Once those functions are working you need to use them in the /sign-up route:

  1. Use auth.createUser and auth.saveUserSession in routes/signUp.js. Create the user, then save the session, then store the session ID in a cookie before redirecting.

You can use the auth.COOKIE_OPTIONS export when you set the cookie. You're going to be setting cookies in multiple places, so it's a good idea to centralise the config.

function post(request, response) {
  const { email, password, name } = request.body;
  auth
    .createUser(email, password, name)
    .then(auth.saveUserSession)
    .then((sid) => {
      response.cookie("sid", sid, auth.COOKIE_OPTIONS);
      response.redirect("/");
    });
  // ...
}

Part three: logging in

User log in is a very similar three-step process:

  1. Get the submitted user data, hash the password, check the hash matches the one you have stored for that user

  2. Create a new session ID, then store the user data in the sessions table (so they're logged in)

  3. Set a cookie containing the session ID so they stay logged in on future requests

Only the first step is different for this route, so you'll need to write just one more function in auth.js.

  1. Write a function verifyUser that takes an email and password as arguments, then gets the stored user from the DB using the email, then uses bcrypt.compare to verify the password. If the passwords match return the user object, otherwise throw an error. For example:

    auth.verifyUser("oli@o.com", "hunter2").then((user) => console.log(user));
    // Logs: { email: "oli@o.com", name: "Oli" }
    // (assuming the password is correct)
function verifyUser(email, password) {
  return model.getUser(email).then((user) => {
    return bcrypt.compare(password, user.password).then((match) => {
      if (!match) {
        throw new Error("Password mismatch");
      } else {
        return user;
      }
    });
  });
}

Once this function is working you need to use it in the /log-in route:

  1. Use auth.verifyUser, auth.saveUserSession and auth.COOKIE_OPTIONS in routes/logIn.js. Verify the user's password, then save the session, then store the session ID in a cookie before redirecting.

function post(request, response) {
  const { email, password } = request.body;
  auth
    .verifyUser(email, password)
    .then(auth.saveUserSession)
    .then((sid) => {
      response.cookie("sid", sid, auth.COOKIE_OPTIONS);
      response.redirect("/");
    });
  // ...
}

Stretch goal: logging out

The POST /log-out route should delete the stored session from the DB, clear the session cookie and redirect back to the home page.

  1. Write a deleteSession function in model.js that takes a session ID and deletes the matching row from the sessions table, returning nothing. For example:

    model.deleteSession("def456").then(() => console.log("done"));
    // Logs: "done"
  2. Use model.deleteSession in the routes/logOut.js. The handler should delete the session and clear the cookie.

Previoussession-authNextsql-intro

Last updated 3 years ago