# Using with Phoenix This guide assumes that you already have an Phoenix application set up with Ash. If you don't then check out the [Phoenix topic on Ash HQ](https://ash-hq.org/docs/guides/ash/2.2.0/topics/phoenix.md). If you haven't already, read {{link:ash_authentication:guide:getting_started_01_basic_setup|Getting started with Ash Authentication}}. This provides a good primer on creating the required resources to use Ash Authentication with your Phoenix app. ## Add to your application's dependencies Bring in the [`ash_authentication_phoenix`](https://github.com/team-alembic/ash_authentication_phoenix) dependency: ```elixir # mix.exs defp deps() [ # ... ____mix_dep_ash_authentication_phoenix____ ] end ``` Use `mix hex.info ash_authentication_phoenix` to quickly find the latest version. ## {{link:ash_authentication_phoenix:module:AshAuthentication.Phoenix.Router}} `ash_authentication_phoenix` includes several helper macros which can generate Phoenix routes for you. They are included by way of a `use` macro: ```elixir # lib/my_app_web/router.ex defmodule MyAppWeb.Router do use MyAppWeb, :router use AshAuthentication.Phoenix.Router pipeline :browser do # ... plug(:load_from_session) end pipeline :api do # ... plug(:load_from_bearer) end scope "/", MyAppWeb do pipe_through :browser sign_in_route sign_out_route AuthController auth_routes_for MyApp.Accounts.User, to: AuthController end end ``` ### {{link:ash_authentication_phoenix:function:AshAuthentication.Phoenix.Router.sign_in_route/3|`sign_in_route/3`}} This helper generates a live route to the `{{link:ash_authentication_phoenix:module:AshAuthentication.Phoenix.SignInLive}}` LiveView. This LiveView renders a generic sign-in/register screen. It is entirely optional, and can be customised either by way of {{link:ash_authentication_phoenix:module:AshAuthentication.Phoenix.Overrides|overrides}} or replaced entirely. ### {{link:ash_authentication_phoenix:function:AshAuthentication.Phoenix.Router.sign_out_route/3|`sign_out_route/3`}} This helper generates a route which points to the `sign_out` action in your `AuthController`. ### {{link:ash_authentication_phoenix:function:AshAuthentication.Phoenix.Router.auth_routes_for/2|`auth_routes_for/2`}} This helper generates all the required routes for all strategies supported by the provided resource. ### Generated routes Given the above configuration you should see the following in your routes: ``` # mix phx.routes auth_path * /auth/user/confirm MyAppWeb.AuthController {:user, :confirm, :confirm} auth_path * /auth/user/password/register MyAppWeb.AuthController {:user, :password, :register} auth_path * /auth/user/password/sign_in MyAppWeb.AuthController {:user, :password, :sign_in} auth_path * /auth/user/password/reset_request MyAppWeb.AuthController {:user, :password, :reset_request} auth_path * /auth/user/password/reset MyAppWeb.AuthController {:user, :password, :reset} auth_path * /auth/user/auth0 MyAppWeb.AuthController {:user, :auth0, :request} auth_path * /auth/user/auth0/callback MyAppWeb.AuthController {:user, :auth0, :callback} auth_path GET /sign-in AshAuthentication.Phoenix.SignInLive :sign_in auth_path GET /sign-out MyAppWeb.AuthController :sign_out ``` ## `{{link:ash_authentication_phoenix:module:AshAuthentication.Phoenix.Controller}}` Instead of using `AshAuthentication.Plug` as suggested in {{link:ash_authentication:guide:getting_started_01_basic_setup|the previous guide}}, `ash_authentication_phoenix` comes with a generator which creates a `Phoenix.Controller` by way of a `use` macro. All functions in {{link:ash_authentication_phoenix:module:AshAuthentication.Phoenix.Plug}} are automatically imported. You can define multiple versions if required (eg one for your `:api` pipeline and another for your `:browser` pipeline). Let's define a version for a browser client: ```elixir # lib/my_app_web/controllers/auth_controller.ex defmodule MyAppWeb.Controllers.AuthController do use MyAppWeb, :controller use AshAuthentication.Phoenix.Controller def success(conn, _activity, user, _token) do return_to = get_session(conn, :return_to) || Routes.path_path(conn, :index) conn |> delete_session(:return_to) |> store_in_session(user) |> assign(:current_user, user) |> redirect(to: return_to) end def failure(conn, _activity, _reason) do conn |> put_status(401) |> render("failure.html") end def sign_out(conn, _params) do return_to = get_session(conn, :return_to) || Routes.path_path(conn, :index) conn |> clear_session() |> redirect(to: return_to) end end ``` ### `success/4` This callback is called when registration or sign-in is successful. You should use it to prepare a response back to the user indicating that authentication was successful. It is called with the following arguments: * `conn` the Plug connection. * `activity` a tuple containing two atoms - the strategy name and the phase. You can use this if you need to provide different behaviour depending on the authentication method. * `user` the authenticated user record (ie an instance of your user resource). * `token` a string containing a JWT for this user, if tokens are enabled. Otherwise `nil`. In the example above we set up the session to know who the user is on their next request and redirect them to an appropriate location. ### `failure/3` This callback is called when registration or sign-in is unsuccessful. You should use this to render an error, or provide some other indication to the user that authentication has failed. It is called with the following arguments: * `conn` the Plug connection. * `activity` a tuple containing two atoms - the strategy name and the phase. You can use this if you need to provide different behaviour depending on the authentication method. * The reason for failure. It _could_ be an `Ash.Error`, an `Ash.Changeset`, or any other failure. In the example above we simply set the HTTP status to 401 and render an HTML page. ### `sign_out/2` This is not strictly necessary, but if you have enabled the {{link:ash_authentication_phoenix:function:AshAuthentication.Phoenix.Router.sign_out_route/3|`sign_out_route/3`}} helper in your router, then this is the controller action which will be called. Use this to perform any sign-out actions (like clearing the session or {{link:ash_authentication_phoenix:function:AshAuthentication.Phoenix.Plug.revoke_bearer_tokens/2|revoking a token}} and then sending the user on their way. ## Component library `ash_authentication_phoenix` ships with a number of components allowing you to pick the level of customisation you require. * {{link:ash_authentication_phoenix:module:AshAuthentication.Phoenix.Components.SignIn}} This is the top-level component, given a [resource configuration](t:AshAuthentication.resource_config) it will iterate through all the configured authentication providers and render their UI. You can place this directly into your sign-in page if you want. * {{link:ash_authentication_phoenix:module:AshAuthentication.Phoenix.Components.Password}} This component renders the UI for password authentication - both the registration and sign-in UI. * {{link:ash_authentication_phoenix:module:AshAuthentication.Phoenix.Components.Password.SignInForm}} This component renders the UI for a password authentication sign-in form. * {{link:ash_authentication_phoenix:module:AshAuthentication.Phoenix.Components.Password.RegisterForm}} This component renders the UI for a password authentication registration form. * {{link:ash_authentication_phoenix:module:AshAuthentication.Phoenix.Components.Password.ResetForm}} This component renders the UI for a user to request a password reset. * {{link:ash_authentication_phoenix:module:AshAuthentication.Phoenix.Components.Password.Input}} This module contains several function components which provide individual input fields and buttons for password authentication. * {{link:ash_authentication_phoenix:module:AshAuthentication.Phoenix.Components.OAuth2}} A component which renders a sign-in button for an OAuth 2.0 provider. ### Overrides All the components above and the {{link:ash_authentication_phoenix:AshAuthentication.Phoenix.SignInLive}} LiveView are customisable via the {{link:ash_authentication_phoenix:AshAuthentication.Phoenix.Overrides}} system. Overrides allow you to configure CSS classes and other options for the components without needing to modify them. ### Tailwind If you plan on using our default [Tailwind](https://tailwindcss.com/)-based components without overriding them you will need to modify your `assets/tailwind.config.js` to include the `ash_authentication_phoenix` dependency: ```javascript module.exports = { content: [ // Other paths. "../deps/ash_authentication_phoenix/**/*.ex" ] } ``` ## Summary In this guide we've learned how to add Ash Authentication to Phoenix, configure routes and handle authentication.