Authentication
You can of course bolt a third-party authentication library onto a
Phoenix project, but in 1.8 you usually do not need to. The built-in
mix phx.gen.auth generator scaffolds a complete authentication
system, complete with magic link sign-in, optional password login,
email confirmation, session management, and scopes for secure data
access.
This chapter walks you through generating that system, running the tests, and seeing the sent emails in your browser during development (no external SMTP server needed).
Running the generator
Create a fresh Phoenix app that includes Ecto (authentication needs a database):
$ mix phx.new auth_demo
$ cd auth_demo
$ mix ecto.create
Then run the phx.gen.auth generator. Accounts is the name of the
context, User the schema, and users the table:
$ mix phx.gen.auth Accounts User users (1)
[...]
* creating priv/repo/migrations/...create_users_auth_tables.exs
* creating lib/auth_demo/accounts/user_notifier.ex
* creating lib/auth_demo/accounts/user.ex
* creating lib/auth_demo/accounts/user_token.ex
* creating lib/auth_demo/accounts.ex
* creating lib/auth_demo_web/user_auth.ex
* creating lib/auth_demo_web/controllers/user_session_controller.ex
[...]
| 1 | Besides the schema, context, and migrations, the generator adds a
full set of LiveView-powered registration, login, and settings pages,
plus a user_auth.ex plug that enforces authentication. |
Phoenix 1.8’s default flow is magic-link: users enter their email, get a single-use link, and log in by clicking it. Password login is opt-in and can be enabled by the user from the settings screen.
Finish the install:
$ mix deps.get
$ mix ecto.migrate
$ mix test (1)
$ mix phx.server (2)
| 1 | The generator ships with a comprehensive test suite. All tests should pass out of the box. |
| 2 | Start the server and open http://localhost:4000. You will see
Log in and Register links in the page header. |
Watching emails land locally
The generator uses Swoosh for mail, which is
bundled with Phoenix. In development Swoosh uses the Swoosh.Adapters.Local
adapter, so nothing is sent over the network. Instead, emails are
available on the Swoosh mailbox route that Phoenix 1.8 mounts by
default:
http://localhost:4000/dev/mailbox
Sign up a new user through the UI, then open /dev/mailbox in the
browser. You will see the confirmation email with the magic link.
Click it, and you are logged in.
The mailbox route is only enabled in development (Application.compile_env(:auth_demo, :dev_routes)).
Production emails require a real adapter such as Swoosh.Adapters.SMTP,
Swoosh.Adapters.Postmark, or Swoosh.Adapters.Sendgrid. The Swoosh
docs list them all.
|
Scopes: secure data access by default
Phoenix 1.8 introduces scopes together with phx.gen.auth. A scope
is a struct that travels through your controllers and LiveViews and
carries the current user. The generator produces functions such as
Accounts.list_notes(scope) instead of Accounts.list_notes(user).
That shape makes it natural to add tenant-based access, role checks, or
multi-scope composition later without retrofitting the code.
You will see the scope referenced throughout the generated module:
defmodule AuthDemoWeb.UserAuth do
def require_authenticated_user(conn, _opts) do
case conn.assigns.current_scope do (1)
%{user: %User{}} -> conn
_ -> redirect(conn, to: ~p"/users/log_in")
end
end
end
| 1 | The scope is available in both controllers and LiveViews via
@current_scope (template) or conn.assigns.current_scope (controller). |
Swapping to a custom mail adapter (production)
For production you usually want a real sending backend. Edit
config/runtime.exs:
if config_env() == :prod do
config :auth_demo, AuthDemo.Mailer,
adapter: Swoosh.Adapters.SMTP,
relay: System.fetch_env!("SMTP_HOST"),
username: System.fetch_env!("SMTP_USER"),
password: System.fetch_env!("SMTP_PASS"),
ssl: true,
port: 465
end
No code changes are required in user_notifier.ex: the same Elixir
code works with any Swoosh adapter.
Next steps
The generated code is a solid starting point and intentionally
understandable. When you need more (OAuth, SSO, 2FA, API tokens), the
simplest path is usually to extend what the generator produced rather
than swap in a whole new library. The official
mix phx.gen.auth
documentation lists every flag, including --hashing-lib argon2 for
teams that prefer Argon2 over the default bcrypt.