{"id":13507439,"url":"https://github.com/pow-auth/pow","last_synced_at":"2026-01-15T22:19:51.575Z","repository":{"id":32750566,"uuid":"132487656","full_name":"pow-auth/pow","owner":"pow-auth","description":"Robust, modular, and extendable user authentication system","archived":false,"fork":false,"pushed_at":"2025-01-28T22:25:29.000Z","size":2249,"stargazers_count":1662,"open_issues_count":70,"forks_count":160,"subscribers_count":31,"default_branch":"main","last_synced_at":"2026-01-13T04:06:24.493Z","etag":null,"topics":["authentication","authorization","elixir","phoenix","user-management"],"latest_commit_sha":null,"homepage":"https://powauth.com","language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pow-auth.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-05-07T16:27:27.000Z","updated_at":"2025-12-18T13:14:40.000Z","dependencies_parsed_at":"2024-03-04T00:27:00.868Z","dependency_job_id":"838cbc31-7321-4921-a0c4-e3d3d549e196","html_url":"https://github.com/pow-auth/pow","commit_stats":{"total_commits":992,"total_committers":65,"mean_commits":"15.261538461538462","dds":"0.18145161290322576","last_synced_commit":"801408e7ce74ecfd85aae1ecc0380187ddb25c3c"},"previous_names":["danschultzer/pow"],"tags_count":40,"template":false,"template_full_name":null,"purl":"pkg:github/pow-auth/pow","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pow-auth%2Fpow","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pow-auth%2Fpow/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pow-auth%2Fpow/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pow-auth%2Fpow/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pow-auth","download_url":"https://codeload.github.com/pow-auth/pow/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pow-auth%2Fpow/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28472626,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-15T22:13:38.078Z","status":"ssl_error","status_checked_at":"2026-01-15T22:12:11.737Z","response_time":62,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["authentication","authorization","elixir","phoenix","user-management"],"created_at":"2024-08-01T02:00:33.588Z","updated_at":"2026-01-15T22:19:51.553Z","avatar_url":"https://github.com/pow-auth.png","language":"Elixir","readme":"# ![Pow](assets/logo-full.svg)\n\n[![Github CI](https://github.com/pow-auth/pow/workflows/CI/badge.svg)](https://github.com/pow-auth/pow/actions?query=workflow%3ACI)\n[![hexdocs.pm](https://img.shields.io/badge/api-docs-green.svg?style=flat)](https://hexdocs.pm/pow)\n[![hex.pm](https://img.shields.io/hexpm/v/pow.svg?style=flat)](https://hex.pm/packages/pow)\n\nPow is a robust, modular, and extendable authentication and user management solution for Phoenix and Plug-based apps.\n\n## Features\n\n* User registration\n* Session based authorization\n* [Per Endpoint/Plug configuration](#configuration)\n* [API token authorization](guides/api.md)\n* Mnesia cache with automatic cluster healing\n* [Multitenancy](guides/multitenancy.md)\n* [User roles](guides/user_roles.md)\n* [Extendable](#extensions)\n* [I18n](#i18n)\n* [And more](guides/why_pow.md)\n\n## Installation\n\nAdd Pow to your list of dependencies in `mix.exs`:\n\n```elixir\ndefp deps do\n  [\n    # ...\n    {:pow, \"~\u003e 1.0.39\"}\n  ]\nend\n```\n\nRun `mix deps.get` to install it.\n\n## Getting started\n\n### Phoenix app\n\n**Umbrella project**: Check out the [umbrella project guide](guides/umbrella_project.md).\n\nInstall the necessary files:\n\n```bash\nmix pow.install\n```\n\nThis will add the following files to your app:\n\n```bash\nLIB_PATH/users/user.ex\nPRIV_PATH/repo/migrations/TIMESTAMP_create_users.ex\n```\n\nAnd also update the following files:\n\n```bash\nconfig/config.exs\nWEB_PATH/endpoint.ex\nWEB_PATH/router.ex\n```\n\nRun migrations with `mix setup`, start the server with `mix phx.server`, and you can now visit `http://localhost:4000/registration/new` to create a user.\n\n### Modify templates\n\nBy default, Pow exposes as few files as possible.\n\nIf you wish to modify the templates, you can generate them using:\n\n```bash\nmix pow.phoenix.gen.templates\n```\n\nThis will also add `web_module: MyAppWeb` to the configuration in `config/config.exs`.\n\n## Extensions\n\nPow is made so it's easy to extend the functionality with your own complimentary library. The following extensions are included in this library:\n\n* [PowResetPassword](lib/extensions/reset_password/README.md)\n* [PowEmailConfirmation](lib/extensions/email_confirmation/README.md)\n* [PowPersistentSession](lib/extensions/persistent_session/README.md)\n* [PowInvitation](lib/extensions/invitation/README.md)\n\nCheck out the [\"Other libraries\"](#other-libraries) section for other extensions.\n\n### Add extensions support\n\nTo keep it easy to understand and configure Pow, you'll have to enable the extensions yourself.\n\nLet's install the `PowResetPassword` and `PowEmailConfirmation` extensions.\n\nFirst, install extension migrations by running:\n\n```bash\nmix pow.extension.ecto.gen.migrations --extension PowResetPassword --extension PowEmailConfirmation\n```\n\nThen run the migrations with `mix ecto.migrate`. Now, update `config/config.ex` with the `:extensions` and `:controller_callbacks` key:\n\n```elixir\nconfig :my_app, :pow,\n  user: MyApp.Users.User,\n  repo: MyApp.Repo,\n  extensions: [PowResetPassword, PowEmailConfirmation],\n  controller_callbacks: Pow.Extension.Phoenix.ControllerCallbacks\n```\n\nUpdate `LIB_PATH/users/user.ex` with the extensions:\n\n```elixir\ndefmodule MyApp.Users.User do\n  use Ecto.Schema\n  use Pow.Ecto.Schema\n  use Pow.Extension.Ecto.Schema,\n    extensions: [PowResetPassword, PowEmailConfirmation]\n\n  # ...\n\n  def changeset(user_or_changeset, attrs) do\n    user_or_changeset\n    |\u003e pow_changeset(attrs)\n    |\u003e pow_extension_changeset(attrs)\n  end\nend\n```\n\nAdd Pow extension routes to `WEB_PATH/router.ex`:\n\n```elixir\ndefmodule MyAppWeb.Router do\n  use MyAppWeb, :router\n  use Pow.Phoenix.Router\n  use Pow.Extension.Phoenix.Router,\n    extensions: [PowResetPassword, PowEmailConfirmation]\n\n  # ...\n\n  scope \"/\" do\n    pipe_through :browser\n\n    pow_routes()\n    pow_extension_routes()\n  end\n\n  # ...\nend\n```\n\n#### Modify extension templates\n\nTemplates for extensions can be generated with:\n\n```bash\nmix pow.extension.phoenix.gen.templates --extension PowResetPassword --extension PowEmailConfirmation\n```\n\nPlease follow the instructions in [\"Modify templates\"](#modify-templates) to ensure that your custom templates will be used.\n\n### Mailer support\n\nMany extensions require a mailer to have been set up. Let's create a mailer mock module in  `WEB_PATH/mails/pow/mailer.ex`:\n\n```elixir\ndefmodule MyAppWeb.Pow.Mailer do\n  use Pow.Phoenix.Mailer\n  require Logger\n\n  def cast(%{user: user, subject: subject, text: text, html: html, assigns: _assigns}) do\n    # Build email struct to be used in `process/1`\n\n    %{to: user.email, subject: subject, text: text, html: html}\n  end\n\n  def process(email) do\n    # Send email\n\n    Logger.debug(\"E-mail sent: #{inspect email}\")\n  end\nend\n```\n\nUpdate `config/config.ex` with `:mailer_backend` key:\n\n```elixir\nconfig :my_app, :pow,\n  # ...\n  mailer_backend: MyAppWeb.Pow.Mailer\n```\n\nThis mailer module will only output the mail to your log, so you can e.g. try out the reset password and email confirmation links. You should integrate the Pow mailer with your actual mailer system. For Swoosh or Bamboo integration, check out the [Configuring mailer guide](guides/configuring_mailer.md).\n\n#### Modify mailer templates\n\nGenerate the template files:\n\n```bash\nmix pow.extension.phoenix.mailer.gen.templates --extension PowResetPassword --extension PowEmailConfirmation\n```\n\nThis will generate template files in the `WEB_PATH/mails/` directory. This will also add the necessary `mail/0` macro to `WEB_PATH/my_app_web.ex` and update the pow config with `web_mailer_module: MyAppWeb`.\n\n## Configuration\n\nPow is built to be modular, and easy to configure. The configuration is passed to function calls as well as plug options, and they will take priority over any environment configuration. It's ideal in case you got an umbrella app with multiple separate user domains.\n\nThe easiest way to use Pow with Phoenix is to use a `:otp_app` in function calls and set the app environment configuration. It will keep a persistent fallback configuration that you configure in one place.\n\n### Module groups\n\nPow has three main groups of modules that each can be used individually, or in conjunction with each other:\n\n#### Pow.Plug\n\nThis group will handle the plug connection. The configuration will be assigned to `conn.private[:pow_config]` and passed through the controller to the users' context module. The Plug module has functions to authenticate, create, update, and delete users, and will generate/renew the session automatically.\n\n#### Pow.Ecto\n\nThis group contains all modules related to the Ecto based user schema and context. By default, Pow will use the `Pow.Ecto.Context` module to authenticate, create, update and delete users with lookups to the database. However, it's straightforward to extend or write your custom user context. You can do this by setting the `:users_context` configuration key.\n\n#### Pow.Phoenix\n\nThis group contains the controllers and templates for Phoenix. You only need to set the (session) plug in `endpoint.ex` and add the routes to `router.ex`. Templates are not generated by default, instead, the compiled templates in Pow are used. You can generate the templates used by running `mix pow.phoenix.gen.templates`. You can also customize flash messages and callback routes by creating your own using `:messages_backend` and `:routes_backend`.\n\nThe registration and session controllers can be changed with your customized versions too, but since the routes are built on compile time, you'll have to set them up in `router.ex` with `:pow` namespace. For minor pre/post-processing of requests, you can use the `:controller_callbacks` option. It exists to make it easier to modify flow with extensions (e.g., send a confirmation email upon user registration).\n\n### Pow.Extension\n\nThis module helps build extensions for Pow. There're three extension mix tasks to generate Ecto migrations and phoenix templates.\n\n```bash\nmix pow.extension.ecto.gen.migrations\n```\n\n```bash\nmix pow.extension.phoenix.gen.templates\n```\n\n```bash\nmix pow.extension.phoenix.mailer.gen.templates\n```\n\n### Authorization plug\n\nPow ships with a session plug module. You can easily switch it out with a different one. As an example, here's how you do that with `Phoenix.Token`:\n\n```elixir\ndefmodule MyAppWeb.Pow.Plug do\n  use Pow.Plug.Base\n\n  @session_key :pow_user_token\n  @salt \"user salt\"\n  @max_age 86400\n\n  def fetch(conn, config) do\n    conn  = Plug.Conn.fetch_session(conn)\n    token = Plug.Conn.get_session(conn, @session_key)\n\n    MyAppWeb.Endpoint\n    |\u003e Phoenix.Token.verify(@salt, token, max_age: @max_age)\n    |\u003e maybe_load_user(conn)\n  end\n\n  defp maybe_load_user({:ok, user_id}, conn), do: {conn, MyApp.Repo.get(User, user_id)}\n  defp maybe_load_user({:error, _any}, conn), do: {conn, nil}\n\n  def create(conn, user, config) do\n    token = Phoenix.Token.sign(MyAppWeb.Endpoint, @salt, user.id)\n    conn  =\n      conn\n      |\u003e Plug.Conn.fetch_session()\n      |\u003e Plug.Conn.put_session(@session_key, token)\n\n    {conn, user}\n  end\n\n  def delete(conn, config) do\n    conn\n    |\u003e Plug.Conn.fetch_session()\n    |\u003e Plug.Conn.delete_session(@session_key)\n  end\nend\n\ndefmodule MyAppWeb.Endpoint do\n  # ...\n\n  plug MyAppWeb.Pow.Plug, otp_app: :my_app\nend\n```\n\n### Ecto changeset\n\nThe user module has a fallback `changeset/2` function. If you want to add custom validations, you can use the `pow_changeset/2` function like so:\n\n```elixir\ndefmodule MyApp.Users.User do\n  use Ecto.Schema\n  use Pow.Ecto.Schema\n\n  schema \"users\" do\n    field :custom, :string\n\n    pow_user_fields()\n\n    timestamps()\n  end\n\n  def changeset(user_or_changeset, attrs) do\n    user_or_changeset\n    |\u003e pow_changeset(attrs)\n    |\u003e Ecto.Changeset.cast(attrs, [:custom])\n    |\u003e Ecto.Changeset.validate_required([:custom])\n  end\nend\n```\n\n### Phoenix controllers\n\nControllers in Pow are very slim and consists of just one `Pow.Plug` function call with response functions. If you wish to change the flow of the `Pow.Phoenix.RegistrationController` and `Pow.Phoenix.SessionController`, the best way is to create your own and modify `router.ex`.\n\nHowever, to make it easier to integrate extension, you can add callbacks to the controllers that do some light pre/post-processing of the request:\n\n```elixir\ndefmodule MyCustomExtension.Phoenix.ControllerCallbacks do\n  use Pow.Extension.Phoenix.ControllerCallbacks.Base\n\n  def before_respond(Pow.Phoenix.RegistrationController, :create, {:ok, user, conn}, _config) do\n    # send email\n\n    {:ok, user, conn}\n  end\nend\n```\n\nYou can add functions for `before_process/4` (before the action happens) and `before_respond/4` (before parsing the results from the action).\n\n#### Testing with authenticated users\n\nTo test with authenticated users in your controller tests, you just have to assign the user to the conn in your setup callback:\n\n```elixir\nsetup %{conn: conn} do\n  user = %User{email: \"test@example.com\"}\n  conn = Pow.Plug.assign_current_user(conn, user, otp_app: :my_app)\n\n  {:ok, conn: conn}\nend\n```\n\n### I18n\n\nAll templates can be generated and modified to use your Gettext module.\n\nFor flash messages, you can create the following module:\n\n```elixir\ndefmodule MyAppWeb.Pow.Messages do\n  use Pow.Phoenix.Messages\n  use Pow.Extension.Phoenix.Messages,\n    extensions: [PowResetPassword]\n\n  import MyAppWeb.Gettext\n\n  def user_not_authenticated(_conn), do: gettext(\"You need to sign in to see this page.\")\n\n  # Message functions for extensions has to be prepended with the snake cased\n  # extension name. So the `email_has_been_sent/1` function from\n  # `PowResetPassword` is written as `pow_reset_password_email_has_been_sent/1`\n  # in your messages module.\n  def pow_reset_password_email_has_been_sent(_conn), do: gettext(\"An email with reset instructions has been sent to you. Please check your inbox.\")\nend\n```\n\nAdd `messages_backend: MyAppWeb.Pow.Messages` to your configuration. You can find all the messages in `Pow.Phoenix.Messages` and `[Pow Extension].Phoenix.Messages`.\n\n### Callback routes\n\nYou can customize callback routes by creating the following module:\n\n```elixir\ndefmodule MyAppWeb.Pow.Routes do\n  use Pow.Phoenix.Routes\n  use MyAppWeb, :verified_routes\n\n  def after_sign_in_path(conn), do: ~p\"/home\"\nend\n```\n\nAdd `routes_backend: MyAppWeb.Pow.Routes` to your configuration. You can find all the routes in `Pow.Phoenix.Routes`.\n\n### Password hashing function\n\n`Pow.Ecto.Schema.Password` is used to hash and verify with Pbkdf2. It's highly recommended to lower the iterations count in your test environment to speed up your tests:\n\n```elixir\nconfig :pow, Pow.Ecto.Schema.Password, iterations: 1\n```\n\nYou can change the password hashing function easily. For example, this is how you use [comeonin with Argon2](https://github.com/riverrun/argon2_elixir):\n\n```elixir\ndefmodule MyApp.Users.User do\n  use Ecto.Schema\n  use Pow.Ecto.Schema,\n    password_hash_verify: {\u0026Argon2.hash_pwd_salt/1,\n                           \u0026Argon2.verify_pass/2}\n\n  # ...\nend\n```\n\n### Current user and sign out link\n\nYou can use `Pow.Plug.current_user/1` to fetch the current user from the connection.\n\nThis can be used to show the sign in or sign out links in your Phoenix template:\n\n```elixir\n\u003c.link :if={Pow.Plug.current_user(@conn)} href={~p\"/session\"} method=\"delete\"\u003eSign out\u003c/.link\u003e\n\u003c.link :if={is_nil Pow.Plug.current_user(@conn)} navigate={~p\"/registration/new\"}\u003eRegistration\u003c/.link\u003e\n\u003c.link :if={is_nil Pow.Plug.current_user(@conn)} navigate={~p\"/session/new\"}\u003eSign In\u003c/.link\u003e\n```\n\nThe current user can also be fetched by using the template assigns set in the configuration with `:current_user_assigns_key` (defaults to `@current_user`).\n\n## Plugs\n\n### Pow.Plug.Session\n\nEnables session-based authorization. The user struct will be collected from a cache store through a GenServer using a unique token generated for the session. The token will be reset every time the authorization level changes (handled by `Pow.Plug`) or after a certain interval (default 15 minutes).\n\nThe user struct fetched can be out of sync with the database if the row in the database is updated by actions outside Pow. In this case, it's recommended to [add a plug](guides/sync_user.md) that reloads the user struct and reassigns it to the connection.\n\nCustom metadata can be set for the session by assigning a private `:pow_session_metadata` key in the conn. Read the `Pow.Plug.Session` module docs for more details.\n\n#### Cache store\n\nBy default `Pow.Store.Backend.EtsCache` is started automatically and can be used in development and test environment.\n\nFor a production environment, you should use a distributed, persistent cache store. Pow makes this easy with `Pow.Store.Backend.MnesiaCache`. To start MnesiaCache in your Phoenix app, add it to your `application.ex` supervisor:\n\n```elixir\ndefmodule MyApp.Application do\n  use Application\n\n  def start(_type, _args) do\n    children = [\n      MyApp.Repo,\n      MyAppWeb.Endpoint,\n      Pow.Store.Backend.MnesiaCache\n      # # Or in a distributed system:\n      # {Pow.Store.Backend.MnesiaCache, extra_db_nodes: {Node, :list, []}},\n      # Pow.Store.Backend.MnesiaCache.Unsplit # Recover from netsplit\n    ]\n\n    opts = [strategy: :one_for_one, name: MyAppWeb.Supervisor]\n    Supervisor.start_link(children, opts)\n  end\n\n  # ...\nend\n```\n\nUpdate `config/config.ex` with `:cache_store_backend` key:\n\n```elixir\nconfig :my_app, :pow,\n  # ...\n  cache_store_backend: Pow.Store.Backend.MnesiaCache\n```\n\nRemember to add `:mnesia` to your `:extra_applications` so it'll be available for your release build. Mnesia will write files to the current working directory. The path can be changed with `config :mnesia, dir: ~c\"/path/to/dir\"`.\n\nThe MnesiaCache requires write access. If you've got a read-only file system you should take a look at the [Redis cache backend store guide](guides/redis_cache_store_backend.md).\n\n### Pow.Plug.RequireAuthenticated\n\nWill halt connection if no current user is not present in assigns. Expects an `:error_handler` option.\n\n### Pow.Plug.RequireNotAuthenticated\n\nWill halt connection if a current user is present in assigns. Expects an `:error_handler` option.\n\n## Pow security practices\n\nSee [security practices](guides/security_practices.md).\n\n## Other libraries\n\n[PowAssent](https://github.com/pow-auth/pow_assent) - Multi-provider support for Pow with strategies for Twitter, Github, Google, Facebook and more\n\n## Contributing\n\nPlease read [CONTRIBUTING.md](CONTRIBUTING.md).\n\n## LICENSE\n\n(The MIT License)\n\nCopyright (c) 2018-2019 Dan Schultzer \u0026 the Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n","funding_links":[],"categories":["Authentication","Elixir"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpow-auth%2Fpow","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpow-auth%2Fpow","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpow-auth%2Fpow/lists"}