From 7276165593e3caddff2ea1c453509a791c872f5f Mon Sep 17 00:00:00 2001 From: Zach Daniel Date: Thu, 26 Jan 2023 09:26:14 -0500 Subject: [PATCH] improvement: remove readme contents, add tutorial (#81) --- README.md | 80 +----- config/dev.exs | 5 +- ...started-with-ash-authentication-phoenix.md | 248 ++++++++++++++++++ 3 files changed, 256 insertions(+), 77 deletions(-) create mode 100644 documentation/tutorials/getting-started-with-ash-authentication-phoenix.md diff --git a/README.md b/README.md index d35ed8b..5d7cf78 100644 --- a/README.md +++ b/README.md @@ -10,83 +10,11 @@ The `ash_authentication_phoenix` package extends adding router helpers, plugs and behaviours that makes adding authentication to an existing Ash-based Phoenix application dead easy. -## Warning - -This is **beta** software. Please don't use it without talking to us! - -## Installation - -The package can be installed by adding `ash_authentication_phoenix` to your list -of dependencies in `mix.exs`: - -```elixir -def deps do - [ - {:ash_authentication_phoenix, "~> 1.4.4"} - ] -end -``` - -If you wish to use our default [Tailwind](https://tailwindcss.com/)-based -components, you will need to add the path to `ash_authentication_phoenix`'s -components in your `assets/tailwind.config.js`: - -```javascript -module.exports = { - content: [ - // Other paths. - "../deps/ash_authentication_phoenix/**/*.ex" - ] -} -``` - -## Usage - -This package assumes that you have [Phoenix](https://phoenixframework.org/), -[Ash](https://ash-hq.org/) and -[AshAuthentication](https://github.com/team-alembic/ash_authentication) -installed and configured. See their individual documentation for details. - -This package is designed so that you can choose the level of customisation -required. At the easiest level of configuration, you can just add the routes -into your router: - -```elixir -defmodule MyAppWeb.Router do - use MyAppWeb, :router - use AshAuthentication.Phoenix.Router - - pipeline :browser do - # ... - plug(:load_from_session) - end - - scope "/" do - pipe_through :browser - sign_in_route - sign_out_route MyAppWeb.AuthController - auth_routes_for MyApp.Accounts.User, to: MyAppWeb.AuthController - end -end -``` - -This will give you a generic sign-in/registration page and store the -authenticated user in the Phoenix session. - -### Customisation - -There are several methods of customisation available depending on the level of -control you would like: - - 1. Use the [generic sign-in liveview](https://hexdocs.pm/ash_authentication_phoenix/AshAuthentication.Phoenix.SignInLive.html). - 2. Apply [overrides](https://hexdocs.pm/ash_authentication_phoenix/AshAuthentication.Phoenix.Overrides.html) - to set your own CSS classes for all components. - 3. Build your own sign-in pages using the pre-defined components. - 4. Build your own sign-in pages using the generated `auth` routes. - ## Documentation -Documentation for the latest release will be [available on +See the [official documentation](https://ash-hq.org) for more. + +Additionally, documentation for the latest release will be [available on hexdocs](https://hexdocs.pm/ash_authentication_phoenix) and for the [`main` branch](https://team-alembic.github.io/ash_authentication_phoenix). @@ -96,6 +24,6 @@ branch](https://team-alembic.github.io/ash_authentication_phoenix). * Please use [conventional commits](https://www.conventionalcommits.org/en/v1.0.0/) - this allows us to dynamically generate the changelog. * Feel free to ask any questions on out [GitHub discussions page](https://github.com/team-alembic/ash_authentication_phoenix/discussions). -## Licence +## License MIT diff --git a/config/dev.exs b/config/dev.exs index 9f9adcc..180709a 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -5,7 +5,10 @@ config :git_ops, changelog_file: "CHANGELOG.md", repository_url: "https://github.com/team-alembic/ash_authentication_phoenix", manage_mix_version?: true, - manage_readme_version: "README.md", + manage_readme_version: [ + "README.md", + "documentation/tutorials/getting-started-with-ash-authentication-phoenix.md" + ], version_tag_prefix: "v" config :ash_authentication_phoenix, DevWeb.Endpoint, diff --git a/documentation/tutorials/getting-started-with-ash-authentication-phoenix.md b/documentation/tutorials/getting-started-with-ash-authentication-phoenix.md new file mode 100644 index 0000000..5882f27 --- /dev/null +++ b/documentation/tutorials/getting-started-with-ash-authentication-phoenix.md @@ -0,0 +1,248 @@ +# Getting Started Ash Authentication 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/latest/topics/phoenix). + + +## Before continuing + +If you haven't already, read and follow [Getting Started with Ash Authentication](https://ash-hq.org/docs/guides/ash_authentication/latest/tutorials/getting-started-with-authentication). You will use the things you create there in this tutorial. + +## Add to your application's dependencies + +```elixir +# mix.exs + +defp deps() +[ + # ... + {:ash_authentication_phoenix, "~> 1.4.4"} +] +end +``` + +Add `ash_authentication_phoenix` to your `.formatter.exs`: + +```elixir +# .formatter.exs + +[ + # ... + import_deps: [:ash_authentication_phoenix] +] +``` + +## Phoenix 1.7 compatibility + +In `your_app_web.ex` you will need to change `helpers: false` to `helpers: true` in the router section. AshAuthenticationPhoenix relies on +these helpers to know where your authenticated routes are. + +## `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 +``` + +### `AshAuthentication.Phoenix.Router.sign_in_route/3` + +This helper generates a live route to the `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 `AshAuthentication.Phoenix.Overrides` or replaced entirely. + +### `AshAuthentication.Phoenix.Router.sign_out_route/3` + +This helper generates a route which points to the `sign_out` action in your `AuthController`. + +### `AshAuthentication.Phoenix.Router.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 GET /sign-in AshAuthentication.Phoenix.SignInLive :sign_in +auth_path GET /sign-out MyAppWeb.AuthController :sign_out +``` + +## `AshAuthentication.Phoenix.Controller` + +Instead of using `AshAuthentication.Plug` as +suggested in [the previous guide](/documentation/tutorials/getting-started-with-authentication.md), +`ash_authentication_phoenix` comes with a generator which creates a +`Phoenix.Controller` by way of a `use` macro. + +All functions in `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: + +> Remember to define an appropriate template in `failure.html.heex` for your +> controller. Alternatively, you could redirect with a flash message. + +```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 +`AshAuthentication.Phoenix.Router.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 `AshAuthentication.Phoenix.Plug.revoke_bearer_tokens/2` 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. + + * `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. + * `AshAuthentication.Phoenix.Components.Password` + This component renders the UI for password authentication - both the + registration and sign-in UI. + * `AshAuthentication.Phoenix.Components.Password.SignInForm` + This component renders the UI for a password authentication sign-in form. + * `AshAuthentication.Phoenix.Components.Password.RegisterForm` + This component renders the UI for a password authentication registration + form. + * `AshAuthentication.Phoenix.Components.Password.ResetForm` + This component renders the UI for a user to request a password reset. + * `AshAuthentication.Phoenix.Components.Password.Input` + This module contains several function components which provide individual + input fields and buttons for password authentication. + * `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 `AshAuthentication.Phoenix.SignInLive` +LiveView are customisable via the `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.