Storing JWT Tokens in Express Session

Where did my session go ?!

If you ended up reading this, you are either curious, lost, or like me, totally #$@!%%@) confused. While building a React Application with Sophie we ran into an interesting problem

Problem: How, can, has, store JWT tokens in a session object using Express. I discovered that I can successfully write to the session object, but I can't retrieve the value in subsequent requests.

Background: The application that I am working on is using Rails/Express/React. You're probably wondering why we are using both Express and Rails. The short answer is, this is how were able to make it work. I'm sure there are other solutions to using third-party authorization with a front-end framework, but this is how we solved it. Reach out to me if you have a better solution, please.

Okay . . . back to the good stuff.

After clacking away at the keyboard and doing some googlin' I came across a node-module called express-session. This package allows you to add middleware to your express application by doing the following:

    import express from 'express';
    import bodyParser from 'body-parser';
    import session from 'express-session'

    const app = express();

    app.use(session({
      name: 'server-session-cookie-id',
      secret: 'my express secret',
      saveUninitialized: true,
      resave: true,
        cookie: {
          secure: false,
          maxAge: 2160000000,
          httpOnly: false
      }
    }));

note: I'm leaving out a lot of code here to focus on the problem that I am writing about, you can view the project code here: client-side / server-side

As you can see here we are using the session middleware that we imported in our constant which contains our express application. The session object takes in a few options, name and secret being the only two required fields. You can read about the rest here.

The express-session documentation suggests that in your Express routes you can do something like this to write to your session object:

    app.get('/testRoute', function(req, res) {
      req.session.name = 'Scott Mescudi' 
      console.log(req.session) 

      res.redirect('/')
    })

Here we are adding a key to our object called name with a value of Scott Mescudi. Now, if we go check our log statement we will see this:

Session {
  cookie:
   { path: '/',
     _expires: 2016-11-11T21:31:54.186Z,
     originalMaxAge: 2160000000,
     httpOnly: false,
     secure: false },
  name: 'Scott Mescudi' }

Awesome, right?! So if all goes well, we should be able to log this session in the path that we redirected to and see that Scott Mescudi is nested properly in our session object. Let's check it out.

Session {
  cookie:
   { path: '/',
     _expires: 2016-11-11T21:41:41.770Z,
     originalMaxAge: 2160000000,
     httpOnly: false,
     secure: false } }

Something is missing . . .

Where did our name property go ? I have not totally figured it out, but after hours of logging statements I tried to log the session that we imported from express-session to see if I could derive any useful information from it. Here is what it looks like:

{ [Function: session]
   Store:
    { [Function: Store]
      super_:
      { [Function: EventEmitter]
      EventEmitter: [Circular],
      usingDomains: true,
      defaultMaxListeners: [Getter/Setter],
      init: [Function],
      listenerCount: [Function] } },
  Cookie: [Function: Cookie],
  Session: [Function: Session],
  MemoryStore: { [Function: MemoryStore] super_:   { [Function: Store] super_: [Object] } },

I have a lot of questions about what is going on here but I decided to try and add a key-value pair to this object and see if we can get some persistence across requests:

    app.get('/testRoute', function(req, res) {
      session.name = 'Scott Mescudi' 
      console.log(session) 

      res.redirect('/')
    })

So now instead of adding a key-value to the requests session I added the pair to the session object that we imported. If I go check my logs now I I will see this:

 { [Function: session]
     Store:
       { [Function: Store]
         super_:
      { [Function: EventEmitter]
        EventEmitter: [Circular],
        usingDomains: true,
        defaultMaxListeners: [Getter/Setter],
        init: [Function],
        listenerCount: [Function] } },
    Cookie: [Function: Cookie],
    Session: [Function: Session],
    MemoryStore: { [Function: MemoryStore] super_:   { [Function: Store] super_: [Object] } },
'jwt': '2jd124never4dtake51&)rjameweewalivedf' }

Okay, this looks good, but let's not get our hopes up. Let's hop into our redirect and try to see if we can retrieve the value that we added to this monstrosity.

Redirect route

app.get('/', function(req, res) {
  console.log('session.jwt)
});

Log statement

'2jd124never4dtake51&)rjameweewalivedf'

It works! This is bewildering, but i'm mildly satisfied that it works.

But what if I want to use your hacky solution but I want to store the token in local storage?

Let hacks meet hacks. Say you didn't want to store the token in your Express session after retrieving it from the query params, but you wanted the client to be able to store it in it's local storage. We can achieve that end by doing the following:

I. After receiving the JWT token from Rails redirect to your Express route with a query parameter

        app.get('/testRouteFromRails', function(req, res) {
           res.redirect(/?jwt=${req.query.jwt`)
         })

Here we are redirecting to our root path with a query parameter which contains our JWT token that we received from Rails.

II. Catch the query parameter in your React Component and store it in localStorage/sessionStorage
To Achieve this we are going to install a npm package called jsUri which will let use parse any URL. Here is what my component looks like:

 import URI from 'jsuri'
 import React, { Component } from 'react'

  class HomePage extends Component {
    componentWillMount() { 
      var jwt = new URI(location.search)
                        .getQueryParamValue('jwt')

    sessionStorage.setItem('jwt', jwt)
   }

 }

export default HomePage;

Now, if we go to our browsers console and run the following code:

sessionStorage.getItem('jwt')  

we will see our lovely little JWT token.

 '2jd124never4dtake51&)rjameweewalivedf'

My thoughts exactly.

Also, you should listen to this song by Ta-ku

Show Comments
comments powered by Disqus