Server Side JSON Web Token Implementation with PostgreSQL and Node.

James McCormack
Queers In Tech
Published in
9 min readFeb 25, 2018
These are collector’s items now.

This article is going to walk through the process of creating a JSON Web Token and the Passport strategies needed on the server to authenticate a user. I am using Node.js and Express to create my server.

Have you heard of Stephen Grider? He’s a software engineer and fantastically thorough teacher of many courses on React, Redux, data structures, and more. Whenever I need an in-depth exploration of a new library or framework, I look to see if he has taught it first.

I recently started the authentication module of his Advanced React and Redux course on Udemy as a guide to setting up tokens that can be passed from a server to a React/Redux front end. Why? My team is trying to build a project with that exact setup. I excitedly started this course, only to realize that he was using MongoDB, and our project was committed to PostgreSQL.

Cursory searches for PostgreSQL and JWT did not show promise. So, I went ahead and figured out how to make it work myself, using the course’s overall concepts as a guide, and I am excited to share that knowledge with you. Just a caveat — this article does not include the front end setup, just the backend.

First, briefly — what is a JSON Web Token (commonly called JWT)? Traditionally, a user logs in to a service, a call is made to a backend API, and the server creates a cookie that is sent along to the front end. This cookie will often contain encrypted user data, and whenever a user attempts to access a protected resource, the credentials in the cookie will be sent along to the server in the request.

A JSON web token is similar, but functions slightly differently. It is commonly used with libraries like React, which renders components within the scope of a single page app (even if it mimics a “regular” website with tools like React Router.) When a user signs up, the request is sent to the back end, an encrypted token is created and sent to the browser, and that token gets checked on each subsequent request of a protected resource. This token does not contain much user data — it’s just literally an encrypted string. All changes to a user’s profile happen on the server, but the token just knows that this is a valid user.

Let’s get started! I am going to assume that you have a basic Express server and connection to your PostgreSQL database set up already. I am using pg-promise here, which is an important point, as I later modify the Passport callback functions to work with the returned data from the promises returned from my queries. After that, we are going to need a bunch of packages.

npm install bcrypt jwt-simple passport passport-jwt passport-local

Let’s start with our file structure:

Don’t worry about the getAlbums and getAlbumById files in the action folder — this template is modified from an existing project and it just creates data on the page upon a successful login. Here’s a quick peek at the schema.sql file I’m working with:

I like my color theme!

I am going to continue working forward from our model. In the actions folder, in the signUp.js file, I am going to write and export the query that will create a user in our database:

If you aren’t bothering with Webpack on the back end, just replace that import statement with const db = require('../db) , assuming that you exported your database connection under that name. Next, let’s finish up queries by adding the following two functions into signIn.js:

I used db.oneOrNone here instead of db.one for a very specific reason having to do with the three options Passport gives you for authenticating a user in its callback. More on that later!

I am next going to move along to index.js in our routes folder. This is essentially the way station for all of our routes, and where we insert custom middleware that will block unauthenticated users:

You will notice my linter yelling at me for declaring passportService and never using it. This is a false alarm. You absolutely need to require this file (which we will get to writing) in order for passport to understand which strategy you are passing to it.

Let me break down what we’re doing here a little more. Passport.js is a library used for various authentication strategies, such as OAuth (logging in with Google or Facebook, for example), JWT, and local, which essentially means that your own server is storing and serving authentication credentials. In this file, we are requiring passport, a services files that will contain our strategies, and then setting the value of requireAuth to equal our JWT strategy, which I will explain in length. Then, we are inserting that middleware before the protected route — which is, in this case, some album review pages.

Let’s move over to the controllers folder, and go into authentication.js. This is where our token will be created and we will do most of the work of signing up a new user.

Now we are getting somewhere! This is the top half of this file.

Here, I am requiring jwt-simple, which is the token creation package. I am requiring a config file, which just exports an object with the key of secret and a string of… whatever the heck you want. The important point here is that you put this config file into your .gitignore and never, ever commit it. If a malicious actor gets a hold of it, they can potentially decode your token. I am also importing the createUser query function from earlier, and bcrypt, which is a hashing library for passwords.

The tokenForUser function takes in a user object, and returns an encoded token that is created with a subject (conventionally called sub) set to the user’s id and a timestamp (also conventionally called iat), along with the imported secret. A magical algorithm returns a very long string out of this information. The signin function near the bottom simply takes in a logged in user and calls the tokenForUser function and sends that token along to the front end. It doesn’t do more than that because we’re going to be creating middleware with Passport that handles de-encrypting the hashed password in the relatively near future. The real fun in the file happens in the signUp function:

What are we doing here? We’re getting the user data from the sign up form (or Postman) that is getting passed to the server in the request body. We are declaring a number of saltRounds, which essentially decides to what power bcrypt’s hashing algorithm runs. Caution — it’s not the number of times it hashes, but actually an exponential increase. Ten used to be the standard, and now twelve is the recommended, but if you bump it up too high, it can literally take an entire day to run.

Then we’re saying if that the user sends either no email or no password, don’t even bother querying the database. Hopefully you have form validation set up on the front end, but this covers a case where that hasn’t happened.

Now we hash that password! I am using the promise version of the hashing function here, because I avoid callbacks whenever possible. This takes the user password and the salt and returns a promise that resolves to a string that we can pass into our createUser function in place of the plain text password. Then, createUser either resolves to a shiny newUser object to pass into our tokenForUser function to generate and send a token, or the database has a bad day and doesn’t send anything back, and we catch that error. Whew. Let’s export these signin and signup functions and move along.

Let’s create an authentication.js file in our routes folder, shall we? This will be nice and simple.

routes/authentication.js

The Authentication variable just requires the signin and signup functions we just wrote. requireSignIn is passport middleware we will write shortly that will handle the login request to the server. Note that we are setting session to false because JWTs don’t require sessions on the server. Then, we call the signup function when the user submits a request to the /sign-up post route. The /sign-in route is a little trickier — we are first going to route the user through Passport, and if they pass, they will move on to the signin function, which will pass them a token.

Take heart, for we are almost done! The last big piece of this puzzle is passport.js file in the services folder. It’s a big one, so I am going to break it in half again:

We are going to be using two Passport strategies here — one is the JWT strategy, and the other is the local. The local strategy is going to log our user in on our server. Passport expects particular information about usernames and passwords, so if the variable getting passed from the form varies from username, we need to explicitly tell Passport that. I am using the email as the username, so I passed that in. However, since I am using password for the password, I don’t need to bother telling them.

localLogin is an instance of Passport’s LocalStrategy class. It gets passed the localOptions object we defined and a callback function with the user info and done, which you will see everywhere in Passport and generally async land. Here, I am passing the user email into the verifyUser database query created earlier, and if the user exists, I am comparing the password the user entered into the form against the hashed password returned for that user from the database using bcrypt’s .compare function. This returns a promise that resolves to a boolean. If it’s true, we return Passport’s done function with null and the validUser. Passing that user object along is super important, because remember this line in routes/authentication.js:

router.post('/sign-in', requireSignIn, Authentication.signin)

The Authentication.signin function needs that user to make a token.

Now for the JWT Passport strategy:

First is the JWT options object. jwtFromRequest uses the ExtractJwt method from the jwt-simple package to tell the server where to look for the JWT. In this case, it’s going to be placed in the header under authorization. This function essentially decodes the encrypted JWT and allows us to pull out whatever user id we set, in order to compare it to a real user in the database. The secretOrKey key is the string of random nonsense we placed in the secret object in our config file early.

jwtLogin is a little thornier to understand. We’re implementing a new Passport strategy designed specifically for JWTs. We’re passing it the jwtOptions we just created — saying, “here — this is how you decode the token.” The second argument is a callback function with a payload parameter and done. Payload is the unencrypted token data. Do you remember how we created that token with an object? (Okay, it’s been a while and I’ve thrown a lot at you, so let’s just share that again…):

const tokenForUser = (user) => {
const timestamp = new Date().getTime()
return jwt.encode({sub: user.id, iat: timestamp}, config.secret)
}

So payload.sub is equivalent to the user.id. If we were to console.log payload.iat, we would see the time the token was created printed out.

returnUserById is a database query that does what it says it does. Once the promise resolves and assuming the user is successfully retrieved, we pass that user into Passport, and send them on their merry way to protected resources!

Okay, let’s test this all out. I am going to head over to Postman and sign up a new user.

I almost cried with joy the first time it worked.

Success! Now I am going to change the route to /sign-in and just enter the email and password, and behold the beauty:

Even more tears were shed.

I really, really hope this will be helpful to anyone out there trying to take on this task. As always, constructive criticism and high fives are welcome!

--

--

James McCormack
Queers In Tech

JavaScript wrangler, board game lover, and nerdy believer in love and spreading knowledge.