I made a silly mistake today and I had to share it

September 6, 2023

musings

I’m creating a sample to-do list application using the Jira API for an article I’m writing and I have been getting a very frustrating bug since yesterday.

The Jira API requires you to attach an access token to the Authorization header when making requests.

Because the HTTP protocol doesn't remember anything between requests (it's ✨stateless✨), I'm using the session storage to keep track of the token.

Persisting access tokens in the session

I have this configuration in my middleware to make the session data accessible to incoming requests (I'm using the express-session npm package):

app.use(session({ secret: 'my-secret', resave: false, saveUninitialized: true, cookie: { secure: false, // For http websites maxAge:60 * 60 * 1000 } }))

When Jira returns an access token, I store it in the session like this:

app.get("/auth/callback", async (req, res) => { try { const code = req.query.code; // Perform the OAuth token exchange const accessToken = await performOAuthExchange(code, clientId, clientSecret, redirectUri); // Save the access token in the session req.session.accessToken = accessToken; // Redirect to your frontend page return res.redirect(FRONTEND_REDIRECT_URL); } catch (error) { return res.json({ error: error.message }); } });

Incoming requests can then access and use the token until it expires.

const accessToken = req.session.accessToken;

The mystery: The "User is not authenticated" error

My access token was working in some requests but failing in others and the pattern was not predictable.

I was getting a “User is not authenticated” error, an error message I was throwing when the session did not have an access token.

const accessToken = req.session.accessToken; if (!accessToken) { throw Error("User is not authenticated."); }

This error was puzzling because I was confident that the session had an expiration time of 3600 seconds, and it shouldn't have expired so quickly.

What was going wrong?

After searching the internet like a mad woman thinking I had configured the session wrong or I wasn't saving it correctly, I eventually went to sleep.

Today morning it hit me. I was running the wrong npm script!

See, in my package.json file, I have these two scripts:

"scripts": { "dev": "node index", "dev-watch": "nodemon index" }

I was running the dev-watch script which uses Nodemon to start the server.

Nodemon watches for changes in your code and automatically restarts the server when you save these changes.

So, what does this have to do with the missing access token?

By default, express-session stores session data in a new MemoryStore instance, which essentially means it saves this data on your computer's disk. Unfortunately, <u>this</u> <u>data</u> <u>is</u> <u>volatile and gets wiped clean when the server restarts or shuts down.</u>

So every time I was resaving my file, the session data including the access token was getting deleted.

The simple fix

The solution was simple: I needed to run the server using the node command.

npm run dev

This way, the server wouldn't restart unless I told it to, and my session data would stay intact.

A better fix would be storing the session in a memory-based caching application like Redis.