Oh now I see it works as expected for pages that require authentication…
The problem is only about pages that do not require authentication but I render a conditional login or logout link on them. Logout shows up on them even if the user logget out but clicked the back button.
So the solution would myabe to have two different pages for this case even if there are almost the same. The second will pass through Powauthentication_required plug.
But this means to duplicate more or less a lot of pages. If someone has a nicer solution, I’m all for. ^^
I’m using the template assignment @current_user to check if user is authenticated and to render the buttons I use Routes.pow_session_path/2.
I think it is equivalent to what is said in your link.
Anyway I just pasted exactly the code of the link in my template and I get the same behaviour…
here is my initial code to show login or logout button:
<%= if @current_user do %>
<%= link @current_user.alias, to: Routes.my_profile_path(@conn, :show) %>
<%= link "Déconnexion", to: Routes.pow_session_path(@conn, :delete), method: :delete %>
<% else %>
<%= link "Connexion", to: Routes.pow_session_path(@conn, :new) %>
<% end %>
I should admit that admit it is not a big problem since clicking on the sign_out button won’t make any trouble… The visitor is just redirected to the login page. Another solution I found while googling is to use some js code to disable the browser back button after user logged out.
You need to set the cache control header to prevent the browser cache. You can run Plug.Conn.put_resp_header(conn, "cache-control", "no-cache, no-store, must-revalidate") in a plug for the relevant controllers/actions, or in a plug for the whole endpoint. Back button will fetch cached page unless the server has requested that the page doesn’t get cached.
This is the perfect solution for me. I think I will write a plug that check if the user is authenticated then and only then send the header that tells the browser not to cache the given pages
I would like to preload an association on authenticated user.
Please where can I add the preload instruction for Pow to call it each time an user authenticate?
Edit:
The purpose is to be able to use something like @current_user.profile.avatar in some template later.
Great job! However, I would recommend a plug like this to make it easier for you instead of the custom authenticate/1 method:
defmodule MyAppWeb.LoadProfilePlug do
@doc false
@spec init(any()) :: any()
def init(opts), do: opts
@doc false
@spec call(Conn.t(), atom()) :: Conn.t()
def call(conn, _opts) do
config = Pow.Plug.fetch_config(conn)
case Pow.Plug.current_user(conn, config) do
nil ->
conn
user ->
preloaded_user = MyApp.Repo.preload(user, :profile)
Pow.Plug.assign_current_user(conn, preloaded_user, config)
end
end
end
And then you can call it across your whole endpoint (you could also set it on just the routes where you know will require the profile preloaded):
defmodule MyAppWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :my_app
# ...
plug Plug.Session,
store: :cookie,
key: "_my_app_key",
signing_salt: "secret"
plug Pow.Plug.Session, otp_app: :my_app
plug MyAppWeb.LoadProfilePlug
# ...
end
If you use a custom authenticate/1 method, then you’ll store the profile along with the user struct in the credentials cache so you have to make sure that all updates of the user struct also has the preloaded profile. This means that you should at least also add a custom update/2 method there, since if users update their profile through the pow registration controller, the cached user struct will be updated with the returning struct from update/2. By using a plug you can completely eliminate this since you’ll fetch the profile directly from the DB each time (and this also prevents that the profile can become out of date if there is some action that may update it, but doesn’t refresh the user in the credentials cache).
Newbie pow question here! (Thanks for the awesome work on this by the way)
I just read around a bit about pow and it looks really nice.
I’m working my way trough my first real Phoenix project. I would like to have accounts authentication with users and parent organizations. I have seen in the documentation some examples that mention this (in the invitation section). Is there any introduction level tutorial on how to set it up correctly?
How do you proceed to add actual users from there? I’m trying to find the “recommended” ways for doing these things before hacking my way in and making obvious mistakes.
I can contribute to documentation on this aspect if it’s helpful.
That example is just for custom user schemas. The example is misleading though with the organizations table, and I’ve changed them to mix pow.install -r MyApp.Repo Accounts.Account accounts.
Thanks for this library, it’s a really nice mix of flexible and batteries-included. I’m finding myself struggling a little with a multi-tenancy situation that isn’t using PG schemas - I wonder if you wouldn’t mind giving your thoughts?
Essentially User belongs to Account, but User.email is only unique within the Account. Accounts are segmented by the accessing domain, and there’s some plug middleware in place that pulls the correct Account into the conn.private storage, but I can’t work out a way of ensuring that this gets merged into the User Context for queries etc within Pow without re-implementing the entire context class from scratch. This is an option, but it’s a bit of a rubbish one prefix in repo_opts gets special cased, but would you be interested in a PR that maybe pulled a Ecto queryable or the like from the conn which could be merged in to scope User accesses?
If there’s a system for this already then apologies for having missed it, would love to know what you think!
If you want to handle it yourself by limiting scope, then there is really no way around it. You’ll have to set up a custom context module and custom changeset. A queryable wouldn’t work as for example authenticate uses Repo.get_by/3.
The problem here is that Operations doesn’t provide the config to custom Context implementations, otherwise this would be fine. Schemas/tenants is a perfectly fine approach for mutli-tenancy with small numbers of tenants but proven to be unmaintainable once in the thousands, which is why a more straightforward referential namespacing is desirable.
Would you be open to a PR that conditionally supplies the config to a custom user_context if the functions support the extra argument? It seems strange to me that Pow.Ecto.Context receives the argument but an implementation of it doesn’t.
That’s a good question on Pow.Operations! I’ve created an issue to address that on Github where I also explain the reasoning for not passing config along: https://github.com/danschultzer/pow/issues/283
Feel free to join in there
One solution that would work with the current Pow release is if the params include tenant (e.g. the login/registration form also has a hidden tenant id field). In that case the custom users context would work, and I believe this is the easiest solution. Otherwise you would have to take full control over the flow with custom controllers.
Edit: I think the caveat with thousands of tenants may also be great to add to the multitenancy guide as alternative to repo_opts! After we figure out a solution I would be happy if you could share the solution with me to add to the guide.
By default the session metadata will include a fingerprint that will persist between session renewals. It is also used by PowPersistentSession when creating a new session. New sessions created will invalidate any previous sessions that has the same fingerprint for increased security.
The stores in Pow now accepts term as keys rather than just binary. That is much more Erlang friendly and efficient (closer to how ETS/Mnesia works), and enable lookups like this:
:ets.match(tab, {[:namespace, :key_1, :_], :"_"})
Pow is backwards compatible so it won’t break existing setups. The Redis cache guide has been updated to use the new setup.
The backend stores are now expected to be able to insert multiple objects at once to keep the operation atomic and isolated. This is pretty close to the ETS API and improves Pow.Store.CredentialsCache.put/3 integrity as it inserts three objects at once.
None for PowInvitation, but it should be easy to implement. You just have to set up controllers and call PowInvitation.Plug.create_user/2 and PowInvitation.Plug.update_user/2. You can find more here and here.