-
-
Notifications
You must be signed in to change notification settings - Fork 157
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Understanding Pow + Many Questions around persistent sessions and SSR #557
Comments
Work has been brutal so I haven't had a chance to check up on this before now. Thanks for your patience @Francesco-Lanciana.
Pow has a clear separation between Ecto, Plug and Phoenix. You can easily use Pow in a setup using Phoenix without Ecto. Making the session store depend on Ecto defeats this purpose. This was the primary reason, though there are a few other reasons for not using Ecto/Postgres:
I do realize now that in practice most people would want to keep everything the same place, especially with container based deploys. Looking into making that easier with #562.
You mean delete the cookie from the client? If yes it's to prevent race condition. We just want to reject invalid tokens. If we delete the cookie from the client, we can end up with a race condition where the session was rolled in one request, but another slow request is using the old session id. It would mean that the cookie is deleted even though it was just updated.
The persistent session (refresh token) is single-use. It doesn't need to be rolled every time the refresh token is rolled (though I think that would be more secure). It'll only be rolled when it's used. I think this is safe enough as when a new session is created any previous sessions with the same fingerprint will be deleted. The fingerprint is carried over from the persistent session.
#563 addresses this. The
Yeah, it would cause 401. Pow doesn't handle this situation, but you could let old sessions live for a short while after they have been rolled. I'm unsure how prevalent of an issue this would be, as it seems very application specific. It would only really happen with apps where the end-user opens multiple tabs in quick succession.
It's described here: https://hexdocs.pm/pow/1.0.20/Pow.Plug.Session.html#content It's to track session lifecycle, and ensures that only one session exists throughout the cycle.
The plug session expires when the browser session ends.
It is. The session ID is signed to conform with how all other tokens are handled in Pow. It was a mistake to depend so heavily on
That's possible, but very dependent on the use case. You can set up a custom auth plug to handle the sessions conditionally. The API guide can also give you an alternative idea for how you can tackle this: https://hexdocs.pm/pow/1.0.20/api.html#content There has been some who have used Pow with react app, I think most of them just went the API route. |
Hey thanks for taking the time to write this up! Had a look at #562 and I don't really understand what you mean by "interface requires execution/checking of a match spec" and "converting a match spec into a performant query is difficult or impossible". What's a match spec and why is that the case?
I see, that makes sense. So by that logic would you only ever delete the cookie if the user logged out? Since it would be hard to detect if an old session ID belongs to a slow request.
That's essentially the approach I took. Was unsure about it though because it felt slightly insecure and hacky (the window of time to allow through is arbitrary). I'm not sure how this isn't hit by more people but for me this seems to happen a lot because I batch requests on the client, sending them all at once with Promise.all. -- I don't know if I'm alone in thinking this way but it seems like POW is quite powerful and extensible but out of the box would work for very few people. Using ETS/Mnesia doesn't work nicely in production in a lot of use cases. Caching the user object by default is confusing because it can easily become stale - it feels like premature optimisation. From what I can gather it seems like these choices were made so that it doesn't rely on Ecto by default, but how many people actually use Phoenix without Ecto? |
It's erlang match spec: http://erlang.org/doc/apps/erts/match_spec.html I use that because it's standard erlang, and very performant. The alternative is to use binary namespace, something I did before, but I don't think it's good practice.
I don't think it's too slow for most use cases. It's also used in prod with https://github.com/ZennerIoT/pow_postgres_store
Yeah, it's only deleted in that case.
It is definitely more insecure, but as with all security it's all about your particular setup and threat vectors. You should think in terms of REST for the session handling. The weakest part here is the browser/client.
I've seen it happen before, but it works for most since they have a standard REST app. It becomes an issue with queuing requests as the cookie has already been set in the request header at that point. There are many ways to get around this, and one way is to permit reuse of old sessions (as you have done it). Another one could be to let the authorization be per batch rather than per request in the batch.
That's true. Pow was built with full infrastructure control in mind. For container based approach that doesn't allow persistent disk storage it simply doesn't work. It's unfortunate, and something I'm working on to resolve.
Yeah, I agree. It's something I would like to solve with #563. My original thought process was that it's super easy to just add in the plug (I rather do less than more by default), but I've come to understand that for most it makes sense to always pull the data from DB.
There's a very clear separation between Ecto, Phoenix and Plug modules in Pow. If they depend on each other then it'll become a lot more difficult to extend and customize. The drawback is what you see here. It's a balance, and something I constantly try to improve. Coherence is an example of auth framework that mixes them together. |
#563 has been fixed, though it's a config option you have to turn on, 1.1.0 will have it turned on by default 😄 |
Hello! I'm in the process of seeing if I can switch my auth system to use POW but it's taking a while to wrap my head around Pow and the extensions. I would appreciate if I could have some people look over how I think it works and tell me what I'm not understanding:
By default without any extensions
We have two stores:
Client store = session cookie
Cache = ETS by default
Pow keeps a signed session ID in the client store. When a new request comes in we attempt to fetch the user given the session ID:
Persistent sessions extension
The persistent_session adds another another cookie (called persistent_session by default) and another ETS table by default. This cookie is a refresh token that allows us to renew sessions that have expired. This plug is placed after Pow.Plug.Session and kicks into gear if it detects that no user has been assigned to the connection. In this case it will:
Questions
Thanks in advance for the help!
The text was updated successfully, but these errors were encountered: