Plug.Session workings

We have used the default session store for years in all of our production apps, never needed anything else, until recently. The client wanted persistent sessions (well, not exactly, he wanted user managers to be able to logout other users remotely and themselves, on ‘all devices’).

So we added a db backed session store. Everything works as expected. However, since doing that coincidentally we are seeing more errors in our database replication. Our application consists of a admin environment, mostly crud stuff, which is not often used; and a high-demand, highly available API. Could this be related? That the numerous api requests are creating numerous sessions that are also deleted very fast - since the API requests are stateless.

Now the meat of my question: the session options are defined in endpoint.ex. When is the session store actually accessed? Is this for all requests? Our guess is that only within pipelines that have the :fetch_session plug this would be the case, but we are not sure how it works…

If our assumption is correct, we need to look elsewhere. If not, how can we exclude the session being created at all for api requests?

Thanks!

Well I would think you can just add metrics to the endpoints you’re interested in and see if the session is getting hit?

As for session storage I’d probably immediately reach for Redis. If there’s big traffic on your app – the session-enabled endpoints included – then it’s highly likely a better idea to split up the storage. But that’s just a guess and it’s better for it to be confirmed with metrics.

1 Like

That is correct.

Since your API is stateless and doesn’t need a session, you should disable the :fetch_session plug for the API endpoints. A typical way to do that is by using a different pipeline:

 pipeline :browser do
    plug(:accepts, ["html"])
    plug(:fetch_session)
    plug(:fetch_live_flash)
    plug(:put_root_layout, {MyAppWeb.LayoutView, :root})
    plug(:protect_from_forgery)
    plug(:put_secure_browser_headers)
  end

  pipeline :api do
    plug(:accepts, ["json"])
  end

Just pipe_through your API endpoints through the :api pipeline, and sesssion store won’t be hit

I’m wondering why you move the session store to the db if all you care for is logging out users? You could build that functionality without issue around phx.gen.auth which uses the default cookie based session storage.

The init/1 callback of module plugs may be called at compile time: see Plug — Plug v1.13.4. If that’s actually the case depends on a few different pieces, but I’d suggest working under the assumption that it will be called at compile time.

Out of curiosity, how can you log out the user if you are storing the session only in the cookie?

By not needing to touch the session to logout a user. phx.gen.auth stores tokens in the session, which are maintained in the db - and therefore deletable. Those tokens are checked on each request a users sends to the server. There’s no need to move the whole session storage to the db.

1 Like

Thanks that make sense. So it does store something in the DB - otherwise it would be impossible - I’m relieved! :slight_smile: Sure, no need to move the entire session to DB or Redis.

Tnx, that does confirm our understanding. We have the pipelines in place as you show.

Ah yes, maybe, but kind of seems the same, there is eventually something in the db. Now each user can (if permission is granted) see how many active sessions they have and remove any or all of them.

But @trisolaran was able to confirm our understanding of the fetch_session was correct. Thank you both!

1 Like