Pow: Robust, modular, extendable user authentication and management system

@danschultzer Would Pow play well with multi-tenancy via Triplex in an Umbrella app? Just putting these terms together is giving me a headache :joy:

I can see that the setup for an Umbrella app is fairly similar except that the Ecto installation is done in a Repo app (assuming your Umbrella app is configured that way). But would setting the tenant dynamically have any impact on Pows config? Any gotchas I should be aware of?

Yeah, I think a custom reset password controller will be the easiest to work with in this case.

I had to read up a bit on this, since Iā€™m not familiar with Triplex or have built multi-tenant apps. You can feed the configuration dynamically so you should be able to go most of the way. Maybe it just requires that repo opts can be propagated from the config.

If you donā€™t mind, then I would love to discuss this in an issue on github and come up with a solution for what you need. This is definitely a good use case for Pow.

4 Likes

Iā€™ve opened an issue with proposed solution for multi-tenant apps: https://github.com/danschultzer/pow/issues/139

3 Likes

Thanks. I was meaning to do it today, but you beat me to it.

@danschultzer - thanks for writing Pow. I have been thinking of using Pow going forward instead of my hand rolled user auth setup, and have some extensions in mind already.

When playing with Pow this morning on a fresh umbrella app, I found the current umbrella instructions just a little confusing for the configuration:

  • Use :my_app_web instead of :my_app

I dont believe that phx creates a :my_app_web application anywhere, umbrella or not??

Anyway I documented all the steps of creating a basic umbrella app for use with Pow and pushed up an example repo. Feel free to rip walkthrough the instructions out of the README and add to the Pow repo if you wish.

1 Like

It does. In the apps/myapp_web directory the OTP app is :myapp_web and not :myapp.

2 Likes

An aside, would that name space apply to APIs? I mean, would you have an api_web, or would the preferred convention be api only?

Ohh I gotcha. It is referring to whatever the otp name is of the Phoenix umbrella child app you want to configure - @abitdodgy which can be any name you choose.

Thanks for clearing that up.

Side note if you did create an Phoenix umbrella child app named my_app_web you would end up with a confusing automated folder structure of:

/apps/my_app_web/lib/my_app_web
/apps/my_app_web/lib/my_app_web_web

Naming things is hard.

1 Like

Yep ^^

What I did is to just name it my_app but I knew the essential code will reside in my_app_web.

The assumption was that the mix phx.new --umbrella task was used to create the umbrella phoenix app. Iā€™ve updated the guide to clarify this. You are correct that itā€™s not true if you are setting it up the apps individually. Thanks!

If youā€™re using Phoenix, then it would most likely still be _web, but thatā€™s only because of how the Phoenix generators sets up the apps.

1 Like

How can I login using pow in my tests? Iā€™m thinking of migrating over from coherence because testing seems a bit complicated with coherence.

You only have to assign the user in e.g. the setup callback:

Pow.Plug.assign_current_user(conn, user, otp_app: :my_app)
3 Likes

I encountered a slight issue when following the guide, sorry for the late report.
Please see all the details in the comment I just made on your commit here.

2 Likes

@danschultzer It is me again. :sweat_smile:

While the lock_users guide works fine, I found that the default session_controller wonā€™t use the EnsureNotLockedUser plug when creating a new session.
Well, it is true that adding the guide plug before any route of the app will do the job, but do you recommend using it like that ?

Anyway Iā€™m trying to use a custom session_controller but I find the process a bit complexā€¦
Here is all Iā€™ve read in the docs about it:

The registration and session controllers can be changed with your customized versions too, but since the routes are built on compile time, youā€™ll have to set them up in router.ex with :pow namespace. For minor pre/post-processing of requests, you can use the :controller_callbacks option. It exists to make it easier to modify flow with extensions (e.g., send a confirmation email upon user registration).

So I have a few questions.

  • For custom controllers, is there a way to use the coresponding default controller view and templates?
  • Is just setting up custom controllers in router.ex with :pow namespace will be sufficient for all to work? (I seem to get some errors about view module not foundā€¦)
  • Is using some custom controller, means that we have to update configuration with routes_backend: MyAppWeb.Pow.Routes?
  • Will it be possible to make for noobs some quick guide on a very basic custom controller ? :blush:

Thank you for your work and your time. ^^

I recommend doing that. Add it before the session routes, or add it to endpoint.ex (after the pow session plug).

Hereā€™s the custom controllers guide: https://github.com/danschultzer/pow/blob/master/guides/CUSTOM_CONTROLLERS.md

The ideal setup is that you take full control of the flow rather than depending on Pow. Trying to hack Pow.Phoenix will become pretty complicated and obfuscate what actually goes on. I recommend just using the Pow.Plug methods/modules instead. This way youā€™ll keep your code explicit and easy to understand. You wonā€™t need the routes backend, or ensure router namespace, etc.

However, the controller callbacks can be used as an alternative if itā€™s only some light changes in the flow. It depends. What is it you want to change?

1 Like

I was thinking about a way to prevent users from receiving password reset link if their account is locked. Since in this case they wonā€™t be authenticated (they will only provide an email), the EnsureNotLockedUser plug wonā€™t work here, right ?
So I will have to change a bit the reset_password extension controller.

Thank you, I will take a look at the guide. I didnā€™t notice it before. ^^

2 Likes

Good call! You are right, the plug will only work when users have authenticated. Iā€™ll update the guide with a section on this. This can be handled with a custom controller callback, but Iā€™ll think it through and see if thereā€™s a more explicit way of handling it.

3 Likes

This library is great. Even noob me managed to get it up and working on my project with little trouble. I do have a dumb question though.
I am trying to change the user_id_field from :email to a custom field in the DB (:staffid) I have the schema and everything set up properly and I can access the data from that field through the Pow.Plug. I keep seeing in the readme that the user_id_field can be changed in the config, I just canā€™t figure out where exactly to do that.
Any help would be very much appreciated!

Thatā€™s great!

You can set the :user_id_field in your user schema module as option to the use Pow.Ecto.Schema macro:

defmodule MyApp.Users.User do
  use Ecto.Schema
  use Pow.Ecto.Schema,
    user_id_field: :staffid

  # ...
end

The :staffid column should have unique index in the db. Just to be clear since it sounds like an belongs to association field :smile:

2 Likes

Thank you for the super fast reply, it worked like a charm!

1 Like