{"id":13513863,"url":"https://github.com/pow-auth/pow_assent","last_synced_at":"2025-05-15T21:04:21.683Z","repository":{"id":32814790,"uuid":"142629370","full_name":"pow-auth/pow_assent","owner":"pow-auth","description":"Multi-provider authentication for your Pow enabled app","archived":false,"fork":false,"pushed_at":"2024-07-14T14:50:16.000Z","size":846,"stargazers_count":338,"open_issues_count":30,"forks_count":51,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-05-11T01:35:44.990Z","etag":null,"topics":["basecamp","discord","elixir","facebook","google","instagram","multi-provider","oauth","oauth2","phoenix","slack","social-login","twitter","vk"],"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":null,"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}},"created_at":"2018-07-27T22:41:22.000Z","updated_at":"2025-05-03T13:30:16.000Z","dependencies_parsed_at":"2024-01-05T01:02:02.833Z","dependency_job_id":"1d55c4c6-b51d-40f9-bb1a-fb85f7a27654","html_url":"https://github.com/pow-auth/pow_assent","commit_stats":{"total_commits":359,"total_committers":19,"mean_commits":"18.894736842105264","dds":"0.16991643454038996","last_synced_commit":"9833bc41d3d2f1ae979368212732ce7ba11f2f09"},"previous_names":[],"tags_count":28,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pow-auth%2Fpow_assent","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pow-auth%2Fpow_assent/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pow-auth%2Fpow_assent/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pow-auth%2Fpow_assent/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pow-auth","download_url":"https://codeload.github.com/pow-auth/pow_assent/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254301971,"owners_count":22048002,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["basecamp","discord","elixir","facebook","google","instagram","multi-provider","oauth","oauth2","phoenix","slack","social-login","twitter","vk"],"created_at":"2024-08-01T05:00:39.013Z","updated_at":"2025-05-15T21:04:21.658Z","avatar_url":"https://github.com/pow-auth.png","language":"Elixir","funding_links":[],"categories":["Elixir","Uncategorized"],"sub_categories":["Uncategorized"],"readme":"# ![PowAssent](assets/logo-full.svg)\n\n[![Github CI](https://github.com/pow-auth/pow_assent/workflows/CI/badge.svg)](https://github.com/pow-auth/pow_assent/actions?query=workflow%3ACI)\n[![hexdocs.pm](https://img.shields.io/badge/api-docs-green.svg?style=flat)](https://hexdocs.pm/pow_assent)\n[![hex.pm](https://img.shields.io/hexpm/v/pow_assent.svg?style=flat)](https://hex.pm/packages/pow_assent)\n\n\nUse Google, Github, Twitter, Facebook, or add your custom strategy for authorization to your Pow enabled Phoenix app.\n\n## Features\n\n* Collects required user id field from the user if the user id is missing from the provider\n* Multiple providers can be used for accounts\n  * When removing authentication, user is validated for password or alternative provider\n* You can add your custom strategy with ease\n* Includes all strategies from [`Assent`](https://github.com/pow-auth/assent):\n  * OAuth 1.0 - `Assent.Strategy.OAuth`\n  * OAuth 2.0 - `Assent.Strategy.OAuth2`\n  * OIDC - `Assent.Strategy.OIDC`\n  * Apple Sign In - `Assent.Strategy.Apple`\n  * Auth0 - `Assent.Strategy.Auth0`\n  * Azure AD - `Assent.Strategy.AzureAD`\n  * Basecamp - `Assent.Strategy.Basecamp`\n  * Discord - `Assent.Strategy.Discord`\n  * Facebook - `Assent.Strategy.Facebook`\n  * Github - `Assent.Strategy.Github`\n  * Gitlab - `Assent.Strategy.Gitlab`\n  * Google - `Assent.Strategy.Google`\n  * Instagram - `Assent.Strategy.Instagram`\n  * Slack - `Assent.Strategy.Slack`\n  * Twitter - `Assent.Strategy.Twitter`\n  * VK - `Assent.Strategy.VK`\n  * LINE Login - `Assent.Strategy.LINE`\n\n## Installation\n\nAdd PowAssent to your list of dependencies in `mix.exs`:\n\n```elixir\ndefp deps do\n  [\n    # ...\n    {:pow_assent, \"~\u003e 0.4.18\"},\n\n    # Optional, but recommended for SSL validation with :httpc adapter\n    {:certifi, \"~\u003e 2.4\"},\n    {:ssl_verify_fun, \"~\u003e 1.1\"},\n    # ...\n  ]\nend\n```\n\nRun `mix deps.get` to install it.\n\n## Getting started\n\n### Set up Pow\n\nIt's required to set up [Pow](https://github.com/pow-auth/pow#phoenix-app) first. You can [run these quick setup](guides/set_up_pow.md) instructions if Pow hasn't already been set up.\n\nIf your user schema uses binary id, then run the PowAssent mix task(s) with the `--binary-id` flag.\n\n### Set up PowAssent\n\nInstall the necessary files:\n\n```bash\nmix pow_assent.install\n```\n\nThis will add the following files to your app:\n\n```bash\nLIB_PATH/user_identities/user_identity.ex\nPRIV_PATH/repo/migrations/TIMESTAMP_create_user_identities.ex\n```\n\nAnd also update the following files:\n\n```bash\nCONTEXT_PATH/users/user.ex\nWEB_PATH/router.ex\n```\n\nRun migrations with `mix setup`. The following routes will be available in your app:\n\n```elixir\nGET     /auth/:provider/new                    PowAssent.Phoenix.AuthorizationController :new\nDELETE  /auth/:provider                        PowAssent.Phoenix.AuthorizationController :delete\nGET     /auth/:provider/callback               PowAssent.Phoenix.AuthorizationController :callback\nGET     /auth/:provider/add-user-id            PowAssent.Phoenix.RegistrationController :add_user_id\nPOST    /auth/:provider/create                 PowAssent.Phoenix.RegistrationController :create\n```\n\n### Modified Pow templates\n\nIf you're modifying the Pow templates, then you have to generate the PowAssent template too:\n\n```elixir\nmix pow_assent.phoenix.gen.templates\n```\n\nOtherwise, Pow will raise an error about missing template when the user id field template is shown.\n\n### Provider links\n\nYou can use helpers from `PowAssent.Phoenix.HTML.CoreComponents` to render provider links:\n\n```elixir\n# Minimal\n\u003cPowAssent.Phoenix.HTML.CoreComponents.provider_links conn={@conn} /\u003e\n\n# With styling\n\u003cdiv class=\"space-y-4 bg-white mt-10\"\u003e\n  \u003cPowAssent.Phoenix.HTML.CoreComponents.provider_links conn={@conn}\u003e\n    \u003c:authorization_link :let={provider} class=\"block rounded-lg bg-zinc-600 hover:bg-zinc-700 py-2 px-3 text-sm font-semibold leading-6 text-white w-full text-center\"\u003e\n      \u003c%= Phoenix.Naming.humanize(provider) %\u003e \u003cspan aria-hidden=\"true\"\u003e→\u003c/span\u003e\n    \u003c/:authorization_link\u003e\n  \u003c/PowAssent.Phoenix.HTML.CoreComponents.provider_links\u003e\n\u003c/div\u003e\n```\n\nThis can be used in the `WEB_PATH/controllers/pow/session_html/new.html.heex`, `WEB_PATH/controllers/pow/registration_html/new.html.heex` and `WEB_PATH/controllers/pow/registration_html/edit.html.heex` templates. You may want to import or alias the module in your web module.\n\nBy default \"Sign in with PROVIDER\" link is shown. A \"Remove PROVIDER authentication\" link will be shown instead if the user is signed in and the user already is authorized with the provider.\n\nYou can also use `\u003c.authorization_link conn={@conn} provider={provider} /\u003e` and `\u003c.deauthorization_link conn={@conn} provider={provider} /\u003e` to generate a link for a single provider.\n\n### Setting up a provider\n\n[Assent](https://github.com/pow-auth/assent) provides many strategies that you can use. Let's go through how to set up the Github strategy.\n\nFirst, register [a new app on Github](https://github.com/settings/applications/new) and add `http://localhost:4000/auth/github/callback` as the callback URL. Then add the following to `config/config.exs` and add the client id and client secret (for production keys you would want to set this in `config/prod.secret.exs`):\n\n```elixir\nconfig :my_app, :pow_assent,\n  providers: [\n    github: [\n      client_id: \"REPLACE_WITH_CLIENT_ID\",\n      client_secret: \"REPLACE_WITH_CLIENT_SECRET\",\n      strategy: Assent.Strategy.Github\n    ]\n  ]\n```\n\nNow start (or restart) your Phoenix app, and visit `http://localhost:4000/auth/github/new`.\n\n#### Nonce\n\nFor OIDC requests a nonce may be required. PowAssent can automatically generate the nonce if you pass `nonce: true` in the PowAssent configuration:\n\n```elixir\nconfig :my_app, :pow_assent,\n  providers: [\n    example: [\n      client_id: \"REPLACE_WITH_CLIENT_ID\",\n      base_url: \"https://server.example.com\",\n      authorization_params: [scope: \"user:read user:write\"],\n      nonce: true,\n      strategy: Assent.Strategy.OIDC\n    ]\n  ]\n```\n\n## Custom provider\n\nYou can add your own custom strategy. See [\"Custom Provider\" section of Assent readme](https://github.com/pow-auth/assent#custom-provider) for more.\n\n## I18n\n\nThe template can be generated and modified to use your Gettext module with `mix pow_assent.phoenix.gen.templates`\n\nFor flash messages, you should add them to your `Pow.Phoenix.Messages` module the same way as all Pow extension flash messages:\n\n```elixir\ndefmodule MyAppWeb.Pow.Messages do\n  use Pow.Phoenix.Messages\n  use Pow.Extension.Phoenix.Messages,\n    extensions: [PowAssent]\n\n  import MyAppWeb.Gettext\n\n  # ...\n\n  def pow_assent_signed_in(conn) do\n    provider = Phoenix.Naming.humanize(conn.params[\"provider\"])\n\n    gettext(\"You've been signed in with %{provider}.\", provider)\n  end\nend\n```\n\nAdd `messages_backend: MyAppWeb.Pow.Messages` to your Pow configuration. You can find all messages in `PowAssent.Phoenix.Messages`.\n\n## Populate fields\n\nTo populate fields in your user struct that are fetched from the provider, you can override the `user_identity_changeset/4` method to cast them:\n\n```elixir\ndefmodule MyApp.Users.User do\n  use Ecto.Schema\n  use Pow.Ecto.Schema\n  use PowAssent.Ecto.Schema\n\n  schema \"users\" do\n    field :custom_field, :string\n\n    pow_user_fields()\n\n    timestamps()\n  end\n\n  def user_identity_changeset(user_or_changeset, user_identity, attrs, user_id_attrs) do\n    user_or_changeset\n    |\u003e Ecto.Changeset.cast(attrs, [:custom_field])\n    |\u003e pow_assent_user_identity_changeset(user_identity, attrs, user_id_attrs)\n  end\nend\n```\n\nThe fields available can be found in the `normalize/2` method of the strategy module.\n\n## Disable registration\n\nYou can disable registration by using `pow_assent_authorization_routes/0` instead of `pow_assent_routes/0` in `router.ex`:\n\n```elixir\ndefmodule MyAppWeb.Router do\n  use MyAppWeb, :router\n  use Pow.Phoenix.Router\n  use PowAssent.Phoenix.Router\n\n  # ...\n\n  pipeline :skip_csrf_protection do\n    plug :accepts, [\"html\"]\n    plug :fetch_session\n    plug :fetch_flash\n    plug :put_secure_browser_headers\n  end\n\n  # ...\n\n  scope \"/\" do\n    pipe_through :skip_csrf_protection\n\n    pow_assent_authorization_post_callback_routes()\n  end\n\n  scope \"/\" do\n    pipe_through :browser\n\n    pow_routes()\n    pow_assent_authorization_routes()\n  end\n\n  # ...\nend\n```\n\nPowAssent will pick it up in the authorization flow, and prevent creating a user if the registration path is missing.\n\n## Cookie options\n\nCookie options are passed on to `Plug.Conn.html.put_resp_cookie/4` and can be set by using the `:auth_session_cookie_opts` setting (and `:reauthorization_cookie_opts` for the `PowAssent.Plug.Reauthorization` plug):\n\n```elixir\nconfig :my_app, :pow_assent,\n    auth_session_cookie_opts: [\n      secure: true,\n      extra: \"SameSite=Strict\"\n    ]\n\n    # If you are using the reathorization plug:\n    # reauthorization_cookie_opts: [\n    #   secure: true\n    # ]\n  ]\n]\n```\n\n## HTTP Adapter\n\nBy default Erlangs built-in `:httpc` is used for requests. SSL verification is automatically enabled when `:certifi` and `:ssl_verify_fun` packages are available. `:httpc` only supports HTTP/1.1.\n\nIf you would like HTTP/2 support, you should consider adding [`Mint`](https://github.com/elixir-mint/mint) to your project.\n\nUpdate `mix.exs`:\n\n```elixir\ndefp deps do\n  [\n    # ...\n    {:mint, \"~\u003e 1.0\"},\n    {:castore, \"~\u003e 0.1.0\"}, # Required for SSL validation\n    # ...\n  ]\nend\n```\n\nUpdate the PowAssent configuration with:\n\n```elixir\nconfig :my_app, :pow_assent,\n  http_adapter: Assent.HTTPAdapter.Mint\n```\n\n## Different module naming\n\nPowAssent works by the assumption that you name your schema modules in the form of `[App].[Context].[Schema]`. If you have a different module naming, all you have to do is to add the `has_many` association to your user module like so:\n\n```elixir\ndefmodule MyApp.Lib.User do\n  use Ecto.Schema\n  use Pow.Ecto.Schema\n  use PowAssent.Ecto.Schema\n\n  schema \"users\" do\n    has_many :user_identities,\n      MyApp.Lib.UserIdentity,\n      on_delete: :delete_all,\n      foreign_key: :user_id\n\n    pow_user_fields()\n\n    # ...\n\n    timestamps()\n  end\n\n  # ..\nend\n```\n\nOtherwise you'll get an error that reads:\n\n```elixir\nwarning: invalid association `user_identities` in schema MyApp.Lib.User: associated schema MyApp.UserIdentities.UserIdentity does not exist\n```\n\n## Callback URL with HTTPS behind proxy\n\nPowAssent uses the Phoenix URL generator to generate the callback URL used in OAuth and OIDC flows. If you run your Phoenix app behind a proxy, then you should ensure that HTTPS endpoints are generated:\n\n```elixir\nconfig :my_app, MyAppWeb.Endpoint,\n  # ..,\n  url: [scheme: \"https\", host: \"example.com\", port: 443]\n```\n\n## Pow Extensions\n\n### PowEmailConfirmation\n\nThe e-mail fetched from the provider params is assumed confirmed if an `email_verified` key with value `true` also exists in the params. In that case the user will have `:email_confirmed_at` set. If `email_verified` isn't `true` in the provider params, or the user provides the e-mail, then the user will have to confirm their e-mail before they can sign in.\n\nTo prevent user enumeration attacks whenever there is a unique constraint error for e-mail the user will see confirmation required error message. However if `email_verified` is `true` in the provider params they will be see the form with changeset error. The same happens if `pow_prevent_information_leak: false` is set in `conn.private`.\n\n### PowInvitation\n\nPowAssent works out of the box with PowInvitation.\n\nProvider links will have an `invitation_token` query param if an invited user exists in the connection. This will be used in the authorization callback flow to load the invited user. If a user identity is created, the invited user will have the `:invitation_accepted_at` set.\n\n### PowPersistentSession\n\nPowAssent doesn't support `PowPersistentSession`, as it's recommended to let the provider handle persistent session. `PowAssent.Plug.Reauthorization` can be used for this purpose.\n\nYou can enable the reauthorization plug in your `WEB_PATH/router.ex` by adding it to a pipeline:\n\n```elixir\ndefmodule MyAppWeb.Router do\n  use MyAppWeb, :router\n  # ...\n\n  pipeline :browser do\n    plug :accepts, [\"html\"]\n    plug :fetch_session\n    plug :fetch_flash\n    plug :protect_from_forgery\n    plug :put_secure_browser_headers\n    plug PowAssent.Plug.Reauthorization,\n      handler: PowAssent.Phoenix.ReauthorizationPlugHandler\n  end\n\n  # ...\nend\n```\n\nYou can also enable `PowPersistentSession` by using the `PowAssent.Plug.put_create_session_callback/2` method:\n\n```elixir\ndefmodule MyAppWeb.Router do\n  use MyAppWeb, :router\n  # ...\n\n  pipeline :browser do\n    plug :accepts, [\"html\"]\n    plug :fetch_session\n    plug :fetch_flash\n    plug :protect_from_forgery\n    plug :put_secure_browser_headers\n    plug :pow_assent_persistent_session\n  end\n\n  defp pow_assent_persistent_session(conn, _opts) do\n    PowAssent.Plug.put_create_session_callback(conn, fn conn, _provider, _config -\u003e\n      PowPersistentSession.Plug.create(conn, Pow.Plug.current_user(conn))\n    end)\n  end\n\n  # ...\n```\n\n## Security concerns\n\nAll sessions created through PowAssent provider authentication are temporary. However, it's a good idea to do some housekeeping in your app and make sure that you have the level of security as warranted by the scope of your app. That may include requiring users to re-authenticate before viewing or editing their user details.\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","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpow-auth%2Fpow_assent","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpow-auth%2Fpow_assent","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpow-auth%2Fpow_assent/lists"}