Adding Magic Links to phx.gen.auth: a comprehensive guide

Creating a comprehensive magic link authentication solution for Phoenix

originally published Thu Dec 28 2023 00:00:00 GMT+0000 (Coordinated Universal Time)

There's a few existing guides out there on doing magic links in Phoenix, in particular this great post by @JohnElmLabs . I wanted to extend John’s solution a little bit: I did not want any password handling code remaining.

This guide will make a couple assumptions. If they don't match what you want to do, you'll have to adjust some things accordingly. This guide assumes:

  1. You do not want to keep password auth around at all
  2. You want one flow for both logging in and signing up

Show me the code

Here’s a link to the an example commit showing what you need to do.

We can end up deleting:

  • lib/example_web/live/user_confirmation_instructions_live.ex
  • lib/example_web/live/user_confirmation_live.ex
  • lib/example_web/live/user_forgot_password_live.ex
  • lib/example_web/live/user_registration_live.ex
  • lib/example_web/live/user_reset_password_live.ex
  • associated tests
  • and any context functions/other stuff that deals with passwords at all

So the files we’ll be keeping around for authentication are:

  • lib/example_web/live/user_login_live.ex will handle login and registration now
  • lib/example_web/live/user_settings_live.ex will handle email updates

And we’ll have some notable changes:

  • I prefer /login over /users/log_in , and /account over /users/settings , so I’ve renamed them as such
  • I’ve added my simple HTML email code from https://andrewian.dev/blog/phoenix-email-defaults/ (also available in video form )
  • We’ll need a migration to remove hashed_password from the users table, and remove password and hashed_password from the schema

Since this example combines login and registration down to one system, new users get created in an unconfirmed state. You should probably have a mix task or an Oban job or something to remove old unconfirmed users.

Again, this post is just a quick summary. Refer to this commit for the code.

Git Patch

You can also download this commit as a Git patch . If you didn’t know, you can add .patch to the end of a commit url on GitHub and it will format it appropriately! 😎

# download as auth.patch
wget https://github.com/sevensidedmarble/phoenix-magic-links/commit/dd53d7979e1a094562c7b6a699b11b0ed5cc85e1.patch -O auth.patch

# you can then rename the modules
sed -i -e 's/Example/YourApp/g ; s/example/your_app/g' auth.patch

# and then apply with a 3-way diff
git apply -3 auth.patch

# or you can tell git to dump them into the working directory no matter what
git apply --reject auth.patch

You could probably tweak the generator to do just this set of things too, if you really wanted to.

Logging in on multiple devices

One of the biggest problems with magic link authentication, in my opinion, is the problem of ‘what do you do when someone opens the link on their phone’.

In this scenario, it is possible to present the user an interface where they can decide to log in on their phone or not. I’ll probably be adding these details in the future.