machineghost
machineghost

Reputation: 35797

What Makes Express-Session Decide to Start a New Session?

I've got a problem where one place in my code (the authentication part) puts something in the session, and another place in the code tries to access it (my GraphQL API part). The problem is, when the second part tries to get the data, it isn't there.

When I log request.session.id I can see the core problem clearly: in between the two requests the session itself changes. The auth request happens, and does put the data in to session A, but when the graphQL code accesses request.session it gets session B, with no data.

However, this is not a "please debug my code for me" request. Instead, I would just like to understand how the library works, so I can debug myself.

Can anyone please explain how/why express-session decides (presumably on getting a new request) that it should abandon the old session and start a new one? From what I've read it likely has something to do with my domain settings, but I've tried playing with those without success, and really I just want to understand how the library works, specifically in terms of deciding to re-use a session or generate a new one.

Upvotes: 2

Views: 368

Answers (1)

njwags
njwags

Reputation: 1147

@machineghost what a great question! There is a lot of confusion around what the express-session module does and how to configure it. I'll do my best to explain.

I think the confusion around express-sesion originates in the fact that the module is basically just gluing different aspects of a webserver into one place, i.e. req.session, for middleware, routes, and potentially (with help) websocket connections to store and access ephemeral data about the "user" (read session) who is making the request.

The three aspects that the module tries to glue together are http cookies, a shortish term data store, and the javascript object req that is passed around through middleware and routes. To shed some light on how this works think about a "normal" HTTP request that has been given to an Express app which is using the express-session module (ES for short):

  • Express passes the request to ES.
  • ES looks for a cookie that it has set previously. This is the place where the majority of reported bugs arise. ES requires that your application has access to cookies. Incorrect configuration of reverse proxies, CORS, or the Fetch API all potentially stop ES from having access to the cookie it tries to set in HTTP responses. If everyone who encountered a bug in ES opened a debugger, set a break point in the entry to the ES middleware, and looked for the presence of the connect.id cookie - ES would have way less issues reported, IMO. NOTE: you can work around the requirement for cookies, but it's hacky at best.
  • If ES found a cookie, it uses the value to lookup the session in whatever the application has configured in the store option. This could be Redis, or MongoDB, or if you haven't specified it's just in memory in the node process.
  • If ES either didn't find a cookie, or if the lookup didn't return a session, it will create a property on the req object called session that is just an empty object, i.e. {}. Middleware or routes further down the line will all have access to this.
  • ES sets a cookie on the res object as a way for future requests to have the session attached, as described above.
  • ES wraps the req.end method with a function that will check if it should save the req.session object. Options like resave and saveUninitialized will determine if ES saves the session for a given request. NOTE: In the case of HTTP redirects, e.g. 302, the res.end method is not called until after the newly redirected request is made. This means that session data that is set before a redirect is not available to the redirected request. This is a known issue and the workaround is to explicitly save the session before redirecting with req.session.save

Note about websockets

In order to get websockets working with ES, at a basic level, you have to take the session that is attached to the request to change protocols and attach it to the socket for that user. I wrote a simple lib as an example here. Note: this is 5 years old and was created more as a talking point than anything, but if you look through how it works you will get the idea.

I hope all of this helps, thanks for posting!

Upvotes: 6

Related Questions