✒️
SEI 802
  • Introduction
  • About These Notes
  • Syllabus
  • Development Workflow
    • Installfest
      • Mac OSX
      • Linux
      • Git Configuration
      • Sublime Packages
    • Command Line
      • The Terminal
      • Filesystem Navigation
      • File Manipulation
      • Additional Topics
    • Intro to Git
      • Version Control
      • Local Git
      • Remote Git
      • Git Recipes
    • Group Collaboration
      • Git Workflows
      • Project Roles and Tools
    • VS Code Tips & Tricks
  • HTML/CSS
    • HTML
    • CSS Selectors
    • CSS Box Model and Positioning
      • Box Model
      • Display and Positioning
      • Flexbox
      • Grid
      • Flexbox & Grid Games
      • Floats and Clears
      • Additional Topics
    • Advanced CSS
      • Responsive Design
      • Pseudo-Classes/Elements
      • Vendor Prefixes
      • Custom Properties
      • Additional Topics
    • Bootstrap
    • CSS Frameworks
    • Accessibility
  • JavaScript
    • Primitives
    • Arrays
    • Objects
    • Control Flow
      • Boolean Expressions
      • Conditionals
      • Loops
      • Promises
    • Functions
      • Callbacks
      • Timing Functions
      • Iterators
    • DOM and Events
    • DOM Manipulation
    • HTML5 Canvas
    • How To Reduce Redundancy
    • (2019) JavaScript OOP
    • (2016) OOP with Classes
    • (1995) OOP with Prototypes
      • Constructors
      • Prototypes
    • Intro to TDD
    • Scoping
    • Inheritance
      • Prototypal Inheritance
      • Call, Apply, and other Functions
      • ES6 Inheritance
      • Resources
    • Custom Node Modules
    • Additional Topics
      • AJAX, Fetch, and Async/Await
      • AJAX w/JSON and Localstorage
        • AJAX w/JSON
        • Local Storage
      • Async module
      • Data Scraping
  • jQuery
    • Intro
      • DOM Manipulation
      • Reddit Practice
      • Styling
      • Events
    • Plugins
    • AJAX
  • APIs
    • Fetch
    • AJAX w/jQuery
    • AJAX w/Fetch
  • Databases
    • Intro to SQL
    • Advanced SQL
    • MongoDB
      • Intro to NoSQL
      • CRUD in MongoDB
      • Data Modeling
      • Intermediate Mongo
  • Node/Express
    • Node
      • Intro to Node
      • Node Modules
      • Node Package Manager (NPM)
    • Express
      • Intro to Express
        • Routes
        • Views
        • Templates
        • Layouts and Controllers
        • CRUD & REST
          • Get and Post
          • Put and Delete
      • APIs with Express (request)
      • APIs with Express (axios)
    • Sequelize
      • Terminology
      • Setup
      • Using Models
      • Seeding Data
      • Validations and Migrations
      • Resources
      • 1:M Relationships
      • N:M Relationships
    • Express Authentication
      • Research Components
      • Code Components
      • Auth in Theory
        • Sessions
        • Passwords
        • Middleware
        • Hooks
      • Auth in Practice
        • Create the User
        • User Signup
        • Sessions
        • User Login
        • Authorization and Flash messages
    • Testing with Mocha and Chai
    • Mongoose
      • Mongoose Associations
    • JSON Web Tokens
      • Codealong
    • Additional Topics
      • oAuth
      • Geocoding with Mapbox
      • Geocoding and Google Maps
      • Cloudinary
      • Websockets with Socket.io
      • SASS
  • Ruby
    • Intro to Ruby
    • Ruby Exercises
    • Ruby Classes
    • Ruby Testing with Rspec
    • Ruby Inheritance
    • Ruby Data Scraping
  • Ruby on Rails
    • Intro to Rails
    • APIs with Rails
    • Asset Pipeline
    • Rails Auth and 1-M
      • Auth Components
    • Rails N:M
    • ActiveRecord Polymorphism
    • Additional Topics
      • oAuth
      • SASS
      • Rails Mailers
      • Cloudinary
      • Jekyll
  • React (Updated 2019)
    • ES6+/ESNext
      • Const and Let
      • Arrow Functions
      • Object Literals and String Interpolation
      • ES6 Recap
      • ES6 Activity
    • Intro to React
      • Create React App
      • Components and JSX
      • Virtual DOM
      • Props
      • Dino Blog Activity
      • Nested Components
      • Lab: LotR
    • React State
      • Code-Along: Mood Points
      • Code-Along: Edit Dino Blog
      • Lab: Simple Calc
      • Lifting State
    • React Router
      • Browser History/SPAs
      • React Router (lesson and full codealong)
      • Router Lab
    • Fetch and APIs
      • APIs with Fetch and Axios
      • Fetch the Weather
    • React Hooks
    • React LifeCycle
      • Lab: Component LifeCycle
    • React Deployment
    • Additional Topics
      • React Frameworks
        • Material UI Theming
      • Typescript
        • More Types and Syntax
        • Tsconfig and Declaration Files
        • Generics with Linked List
      • Redux
      • TypeScript
      • Context API
      • React Native
  • Meteor
  • Deployment and Config
    • Deploy - Github Pages
    • Deploy - Node/Sequelize
    • Deploy - Node/MongoDB
    • Deploy React
    • Deploy - Rails
      • Foreman (Environment Variables)
    • Deploy - AWS Elastic Beanstalk
    • Deploy - S3 Static Sites
    • Deploy - Django
    • Deploy - Flask
  • Data Structures and Algorithms
    • Recursion
    • Problem Solving - Array Flatten
    • Binary Search
    • Algorithm Complexity
    • Stacks and Queues
    • Bracket Matching
    • Ruby Linked Lists
      • Sample Code
      • Beginner Exercises
      • Advanced Exercises
    • JS Linked Lists
      • Sample Code
      • Beginner Exercises
      • Beginner Solutions
    • Hash Tables
    • Intro to Sorting
    • Insertion Sort
    • Bucket Sort
    • Bubble Sort
    • Merge Sort
    • Quick Sort
    • Heap Sort
    • Sorting Wrapup
    • Hashmaps
    • Trees and Other Topics
  • Python
    • Python Installation
    • Intro to Python
    • Python Lists
    • Python Loops
    • Python Dictionaries
    • Python Sets and Tuples
    • Python Cheatsheet
    • Python Functions
    • Python Classes
    • Python Class Inheritance
    • Intro to Flask
    • Intro to SQLAlchemy
      • Flask and SQLAlchemy
    • Using PyMongo
    • Intro to Django
    • CatCollector CodeAlong
      • URLs, Views, Templates
      • Models, Migrations
      • Model Form CRUD
      • One-to-Many Relations
      • Many-to-Many Relations
      • Django Auth
    • Django Cheatsheet
    • Django Auth
    • Django Polls App Tutorial
    • Django School Tool Tutorial
    • Django 1:M Relationships
    • Custom Admin Views
    • Data Structures and Algorithms
      • Recursion
      • Binary Search
      • Stacks and Queues
      • Linked Lists
      • Binary Trees
      • Bubble Sort
      • TensorFlow & Neural Networks
    • Adjacent Topics
      • Raspberry Pi
      • Scripting
  • Assorted Topics
    • History of Computer Science
    • Regular Expressions
    • Intro to WDI (Course Info)
    • Being Successful in WDI
    • Internet Fundamentals
      • Internet Lab
    • User Stories and Wireframing
      • Wireframing Exercise: Build an Idea
    • Post WDI
      • Learning Resources
      • Deliverables -> Portfolio
      • FAQ
  • Projects
    • Project 1
    • Project 2
    • Project 3
      • Project 3 Pitch Guidelines
    • Project 4
    • Past Projects
      • Project 1
      • Project 2
      • Project 3
      • Project 4
      • Portfolios
    • Post Project 2
    • MEAN Hackathon
      • Part 1: APIs
      • Part 2: Angular
    • Portfolio
  • Web Development Trends
  • Resources
    • APIs and Data
    • Tech Websites
    • PostgreSQL Cheat Sheet
    • Sequelize Cheat Sheet
    • Database Administration
  • Archived Section
    • (Archived) ReactJS
      • Intro to React
        • Todo List Codealong
        • Additional Topics
      • Deploy React
      • React with Gulp and Browserify
        • Setting up Gulp
        • Additional Gulp Tasks
      • React Router
        • OMDB Router
        • OMDB Search
        • Additional Resources
      • React Animations
        • CSS Animations
    • AngularJS
      • Intro to AngularJS
        • Components and SPA
        • Create an Angular App
      • Angular Directives and Filters
      • Angular Animation
      • Angular Bootstrap Directives
        • Bootstrap Modals
      • Angular $http
      • Angular Services
        • Service Recipes
        • ngResource
        • Star Wars Codealong
      • Angular Routing
      • Angular + Express
      • Angular Authentication
        • Additional Topics
      • Angular Components
      • Angular Custom Filters
      • Angular Custom Directives
Powered by GitBook
On this page
  • Starter Express App
  • What's different? - Demo
  • 1. Crafting our JSON Return
  • 2. Encrypting Passwords in the Model
  • The Main Feature, JWTs
  • Creating a token
  • A middleware to check for our token
  • An error handler for when there isn't a token
  • Wait, don't leave us – how do we access it?
  • Conclusion

Was this helpful?

  1. Node/Express
  2. JSON Web Tokens

Codealong

PreviousJSON Web TokensNextAdditional Topics

Last updated 3 years ago

Was this helpful?

Starter Express App

Now, before we talk specifically about JWTs, we've built a really basic starter Express app to hack on for a few minutes. Take 5 minutes to look through it and see what you notice. There are one or two things you might see that are different, but get familiar with what we're working with.

What's different? - Demo

You might notice some interesting things in models/user.js.

1. Crafting our JSON Return

Unless we modify the code, our JSON objects will get returned in our API with every piece of information in the database. But the fact is, you may sometimes want to omit certain things (like password hashes), or you might also just want to have your JSON look a certain way.

One way to do this is to transform your model's schema.

UserSchema.set('toJSON', {
  transform: function(doc, ret, options) {
    var returnJson = {
      id: ret._id,
      email: ret.email,
      name: ret.name
    };
    return returnJson;
  }
});

This is an example of whitelisting, but you could also blacklist if that's easier, by deleting key/value pairs instead:

UserSchema.set('toJSON', {
  transform: function(doc, ret, options) {
    delete ret.password;
    return ret;
  }
});

2. Encrypting Passwords in the Model

// Let's encrypt our passwords using only the model!
// This is a hook, a function that runs just before you save.
UserSchema.pre('save', function(next) {
  var user = this;

  // only hash the name if it has been modified (or is new)
  if (!user.isModified('password')) return next();
  // bcrypt can come up with a salt for us (just pass it a number)
  user.password = bcrypt.hashSync(user.password, 10);

  next();
});

Now, we're going to protect the /api/users route via JWT token authentication. In order to do so, we'll be adding a new route called POST /api/auth in order to create the token. Then, we'll verify each route with the token by passing it in the headers.

The Main Feature, JWTs

We'll have to install a couple npm modules to start working with JWTs & authenticating via tokens.

npm install --save jsonwebtoken express-jwt

Now, of course, we have to require them. Later, you could extract this to a config file if you'd like, but for now let's throw it in index.js:

var express = require('express');
var bodyParser = require('body-parser');
var mongoose = require('mongoose');
var expressJWT = require('express-jwt');
var jwt = require('jsonwebtoken');
var User = require('./models/user');
var app = express();

// A secret phrase that only your app knows, so encryption can be consistent. We'll use this later.
var secret = "mysupersecretpassword";

Now there are 3 things we're going to need to write:

  • An endpoint to create a token

  • A middleware that will check for the token

  • An error handler for when there isn't a token

That's it.

Creating a token

We're going to put our auth route/endpoint right in index.js. You could (and probably should later) extract it out, so that index.js doesn't become cluttered.

Considering we're creating a token, we'll be using the POST HTTP verb.

//index.js
app.post('/api/auth', function(req, res) {
  // some code to check that a user's credentials are right #bcryptmaybe?
  // collect any information we want to include in the token, like that user's info

  // make a token already & send it as JSON
});

Psuedocode successful. Let's fill out these bits.

//index.js
app.post('/api/auth', function(req, res) {
  // some code to check that a user's credentials are right #bcryptmaybe?
  // collect any information we want to include in the token, like that user's info
  User.findOne({email: req.body.email}, function(err, user) {
    if (err || !user) return res.send({message: 'User not found'});
    user.authenticated(req.body.password, function(err, result) {
      if (err || !result) return res.send({message: 'User not authenticated'});

      // make a token & send it as JSON
      var token = jwt.sign(user, secret);
      res.send({user: user, token: token});
    });
  });
});

We'll see that first, we find a user by their email address and see if we get a result. If not, we'll say that the user was not found. Second, we'll authenticate the user using a similar instance method as we did with session authentication. We'll only send back a token if the user is authenticated.

The next part, we're using our jwt library, and it just takes a few arguments. This comes from the documentation, but basically we pass it the payload, aka user, and pass it that secret phrase we made earlier (so that tokens can be encrypted consistently), and we have a token.

We should get back something like this:

// http://localhost:3000/api/auth
{
  "user": {
    "id": "5654f779fa0e9c97831c2784",
    "email": "bhague1281@gmail.com",
    "name": "Brian Hague"
  },
  "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6IjU2NTRmNzc5ZmEwZTljOTc4MzFjMjc4NCIsImVtYWlsIjoiYmhhZ3VlMTI4MUBnbWFpbC5jb20iLCJuYW1lIjoiQnJpYW4gSGFndWUifQ.HcL1Cd5wtON15ZlMm7siyi0hvSUe7hsIsfzgvVR7U7c"
}

A middleware to check for our token

Next up, we have to start restricting access. This is suprisingly easy, since we're using expressJWT. It's built in.

Far above your routes, add this in your index.js:

app.use('/api/users', expressJWT({secret: secret}).unless({method: 'POST'}));

Hello, middleware. It sits between the request & your code, and because it's above any routes you have set up, it'll run first.

It uses the library and checks for a token. That's it. If there is a token, it keeps going & runs your app like normal. It throws your user (the payload you embedded in the JWT), into request.user for you.

So on any particular route or controller action, you should be able to say, request.user.name and get back the user's name. You could use that for looking them up in the database, storing their information in an embedded document, whatever you need.

And hopefully it's apparent, but you can customize the URLs you need to restrict. We happened to have chosen this one in particular, but you could easily do the same for all of the users resource, all of your API, or whatever you like.

That's it. Now the last step.

An error handler for when there isn't a token

Technically, our app is good to go. If you try to access one of your users, you won't be able to. You'll see a bunch of junk that looks like this:

Lovely. So our last step is to pretty that up with a little error handling.

Just after your middleware, let's make another tiny little middleware:

// JWT access control. Important to have these before our routes, so it can run first!
app.use('/api/users', expressJWT({secret: secret}).unless({method: 'POST'}));
app.use(function (err, req, res, next) {
  // send an appropriate status code & JSON object saying there was an error, if there was one.
});

We just need an if statement.

// JWT access control. Important to have these before our routes, so it can run first!
app.use('/api/users', expressJWT({secret: secret}).unless({method: 'POST'}));
app.use(function (err, req, res, next) {
  // send an appropriate status code & JSON object saying there was an error, if there was one.
  if (err.name === 'UnauthorizedError') {
    res.status(401).send({message: 'You need an authorization token to view this information.'})
  }
});

Boom! Now let's see what happens when we try to access a user.

Wait, don't leave us – how do we access it?

Last but not least, we need to access the resource.

You've got it all built, and this final piece will complete the puzzle.

You send along your token via an Authorization header, with a value of "Bearer mylongtokengoesrighthere" Try this out using Postman.

If you're using a tool other than CURL, look for where you can add in custom headers:

So, just like a client would have to, you'd:

  1. POST to your authorizations endpoint!

  2. Copy that token!

  3. GET to the users endpoint, with an Authorization header!

And there you have it. It's really only a few lines of code we had to write, and once you combine it with bcrypt and hashed passwords, you've got yourself a secure API that can be authorized with a single string of characters.

Conclusion

  • What is a JWT? Why is useful for authorizing an API?

  • How do you create a JWT in an endpoint in your Express app?

  • How do you secure an endpoint using a JWT?

Finally, we just send the data back to the client. Let's try our endpoint and see if we get a token back, using something like or .

https://github.com/WDI-SEA/express-jwt-users
Insomnia
Postman