silverdr

silverdr

Phx_gen_auth user creation

I am going through the phx_gen_auth output in more details today…

… and another thing caught a bit of my attention:

  def create(conn, %{"user" => user_params}) do
    case Accounts.register_user(user_params) do
      {:ok, user} ->
        {:ok, _} =
          Accounts.deliver_user_confirmation_instructions(
            user, &Routes.user_confirmation_url(conn, :confirm, &1)
          )

        conn
        |> put_flash(:info, "User created successfully.")
        |> UserAuth.log_in_user(user)

      {:error, %Ecto.Changeset{} = changeset} ->
        render(conn, "new.html", changeset: changeset)
    end
  end

is an action in user_registration_controller.ex. It first creates (inserts) the user via Accounts.register_user() and later on creates plus inserts the “confirmation” token and delivers notification via Accounts.deliver_user_confirmation_instructions(). And here’s the doubt: I can easily imagine situation where inserting the token fails but the user is already inserted. Or the notification fails. And the user cannot be re-registered because the email is already taken, and so on.

So… shouldn’t these three be rather run transactionally?

Most Liked

josevalim

josevalim

Creator of Elixir

Yes, putting it in a transaction could be an improvement. But since the email delivery can fail anyway, we have safe retry mechanisms, and the token creation failing being extremely unlikely, so I don’t worry it.

About emailing new tokens, that’s on purpose, cause the token is encrypted, so we can’t recover old ones, and we don’t want to make them stale (as you can receive a late email first).

People flooding others inbox is a possibility. Not much on confirmation, cause it requires an unconfirmed account, but definitely on password recovery. A large app likely requires rate limiting, not only on those screens but also on login, but it has been out of scope so far. :slight_smile: Another idea is to require another information, which is app specific such as date of birth, before resetting the password.

That’s to say, your auditing has been on point. :slight_smile: Perhaps improvements for the future. If you do implement rate limiting, then consider writing a blog post, I am sure it will be helpful.

silverdr

silverdr

Noticed that too. The question is more of “why not wrap it in a transaction and have such scenarios covered?” Is there a reason other than simply “nobody felt a need to”?

As for requesting new token and instruction, there are two aspects that raise a bit of concern to my un-phoenix-trained eye too:

  • said requesting does not seem to require any authorisation (like after authentication/logging-in first for example)
  • upon requesting new token, all the previous ones remain stored in the database. Until the account is “confirmed” (removing of them is nicely transactional, BTW).

Doesn’t that (the latter especially) mean that even a third party can easily flood the database with tons of records, potentially leading to a DOS in an extreme case?

f0rest8

f0rest8

This isn’t really a point-to-be-made but rather sharing my experience (and blog post below) with phx_gen_auth’s design decisions as they relate to my work with Metamorphic.


phx_gen_auth and rate limiting
I implemented a simple session-based rate limiting for log in based on Chris McCord’s post on GenServers and ETS. This also helped me practice and familiarize myself with the whole GenServer/ETS process a bit before employing ETS to handle temporary storage of people’s images on Metamorphic.

Here’s the friend link for free viewing of the post on Medium.

The rate limiting was super easy to implement into my design thanks to phx_gen_auth’s design.


phx_gen_auth and password reset
In regard to password reset, I had a slightly different problem of creating a “zero-knowledge” encrypted system for people’s data.

If someone were to reset their password they would lose access to any data they had previously encrypted. Rather than allow that with ample warnings, I opted to just remove the password reset option altogether (you can still change your password from within your account), because the other options required things that I felt could ultimately lead to an attacker (albeit motivated) creating havoc with a person’s account (one thought was to allow you to reset your password if you use the same machine as when you first registered your account, but all these kinds of solutions come with other security, privacy, and design tradeoffs).

That really didn’t have much to do with phx_gen_auth but I include it because the beauty, in my opinion, of phx_gen_auth is that it understands that people may have quite different needs for their authentication. By laying just the strong foundation, it becomes really easy to quickly customize and adapt the system to fit your needs (be it “more” secure, or remove things altogether).

I think the decisions that were made about phx_gen_auth, and reasoning behind them, were made with a lot of foresight and wisdom from past experiences. And my experience using it has been very positive because of it. Thank you!

Where Next?

Popular in Questions Top

_russellb
I want to try my hand at web scraping. What tools/libraries do I need to use. I’m hoping to turn this into something professional so don’...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
New
electic
Hi, I am new to Elixir. I am trying to use the DateTime component to insert a date into MySQL however the there seems to be no way to fo...
New
mgjohns61585
Could someone help me? I’m making my first elixir program, number guessing game. I can’t figure out how to convert the user’s guess from ...
New
vrod
I am using the Starship cross-shell prompt – it seems pretty nice, but I get some errors: [WARN] - (starship::utils): Executing command ...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
fayddelight
I tried installing elixir 1.11.2 erlang 23.3.4 via asdf in my zsh shell. Enabled the versions locally and globally. When I list them ...
New
JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New

Other popular topics Top

hakarabakara1
I have three modules, a Business which is associated Tags and Categories though join tables business_tags and business_categories. I inte...
New
aesmail
Hello guys, I have finally made it. I created an admin interface for a framework. It’s been on my todo list for years and with the curre...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
gausby
I asked this very same question on twitter and got some interesting feedback, but I thought it would be a good question to ask here as we...
1207 39297 209
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
komlanvi
Hi everyone, I was playing with phoenix liveView but I run into an issue. I have a form and want to validate each input text when the te...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
AstonJ
Seen any cool LiveView demos, sample apps or examples? Please post them here! :003:
New

We're in Beta

About us Mission Statement