{"id":13508080,"url":"https://github.com/bitgamma/plug_auth","last_synced_at":"2025-06-17T09:05:07.053Z","repository":{"id":25167247,"uuid":"28590254","full_name":"bitgamma/plug_auth","owner":"bitgamma","description":"A collection of authentication-related plugs","archived":false,"fork":false,"pushed_at":"2017-06-10T05:50:45.000Z","size":53,"stargazers_count":67,"open_issues_count":0,"forks_count":14,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-05-13T00:06:58.171Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Elixir","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"isc","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bitgamma.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-12-29T11:37:38.000Z","updated_at":"2023-07-14T08:14:26.000Z","dependencies_parsed_at":"2022-08-23T21:20:24.768Z","dependency_job_id":null,"html_url":"https://github.com/bitgamma/plug_auth","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/bitgamma/plug_auth","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitgamma%2Fplug_auth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitgamma%2Fplug_auth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitgamma%2Fplug_auth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitgamma%2Fplug_auth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bitgamma","download_url":"https://codeload.github.com/bitgamma/plug_auth/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bitgamma%2Fplug_auth/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259562312,"owners_count":22876983,"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":[],"created_at":"2024-08-01T02:00:47.651Z","updated_at":"2025-06-17T09:05:07.010Z","avatar_url":"https://github.com/bitgamma.png","language":"Elixir","funding_links":[],"categories":["Framework Components"],"sub_categories":[],"readme":"# PlugAuth\n\nPlugAuth is a collection of authentication-related plugs. It currently performs two tasks:\n\n* Authentication\n* Access control\n\n## Usage\n\nAdd PlugAuth as a dependency in your `mix.exs` file.\n\n```elixir\ndefp deps do\n  [{:plug_auth, \"\u003e= 0.0.0\"}]\nend\n```\n\nYou should also update your applications list to include a webserver (e.g. cowboy), plug and plug_auth:\n\n```elixir\ndef application do\n  [applications: [:cowboy, :plug, :plug_auth]]\nend\n```\n\nAfter you are done, run `mix deps.get` in your shell to fetch the dependencies.\n\n## Authentication\n\nCurrently two authentication methods are supported: HTTP Basic and Token-based. In both cases you will first have to add valid credentials in the credential store. Multiple credentials can be added. The plugs provide convenience methods for this task.\n\n### HTTP Basic Example\n```elixir\ncreds = PlugAuth.Authentication.Basic.encode_credentials(\"Admin\", \"SecretPass\")\nPlugAuth.CredentialStore.Agent.put_credentials(creds, %{role: :admin})\n```\n\n### Token Example\n```elixir\ntoken = PlugAuth.Authentication.Token.generate_token\nPlugAuth.CredentialStore.Agent.put_credentials(token, %{role: :admin})\n```\n\nThe last argument in both cases can be any term, except nil. On successful authentication it will be stored by the authentication plug in the assign map of the connection with the :authenticated_user atom as key\n(unless specified otherwise, see: Plugs Composition Example). You can retrieve it using\n\n```elixir\nPlugAuth.Authentication.Utils.get_authenticated_user(conn)\n```\n\nThe content of this term is not used for authentication purposes, but can be useful to store application specific information about the user (for example, the user id, its role, etc).\n\nTo perform authentication, you can add either plug to your pipeline.\n\n### HTTP Basic Example\n```elixir\nplug PlugAuth.Authentication.Basic, realm: \"Secret\"\n```\nThe realm parameter is optional and can be omitted. By default \"Restricted Area\" will be used as realm name. You can also pass the error parameter, which should be a string or a function. If a string is passed, that string will be sent instead of the default message \"HTTP Authentication Required\" on authentication failure (with status code 401). If a function is passed, that function will be called with one argument, `conn`.\n\n### Token Example\n```elixir\nplug PlugAuth.Authentication.Token, source: :params, param: \"auth_token\", error: ~s'{\"error\":\"authentication required\"}'\n```\nThe error parameter is optional and is treated as in the example above. The source parameter defines how to retrieve the token from the connection. Currently, the three acceptable values are: :params, :header and :session. Their name is self-explainatory. The param parameter defines the name of the parameter/HTTP header/session key where the token is stored. This should cover most cases, but if retrieving the token is more complex than that, you can pass a tuple for the source parameter. The tuple must be in the form `{MyModule, :my_function, [\"param1\", 42]}`. The function must accept a connection as its first argument (which will be injected as the head of the given parameter list) and any other number of parameters, which must be given in the third element of the tuple. If no additional arguments are needed, an empty list must be given.\n\n### Custom Credential Store\n```elixir\nplug PlugAuth.Authentication.Basic, realm: \"Secret\", store: MyApp.MyCredentialStore\n```\n\n```elixir\ndefmodule MyApp.MyCredentialStore do\n  @behaviour PlugAuth.CredentialStore\n\n  def get_user_data(_credentials) do\n    :joe\n  end\n```\n\nBy default, `PlugAuth.CredentialStore.Agent` is a bare `GenServer` interface, thus no\nstate persistence is provided between application restarts.\n\nA custom credentials store is a module implementing `PlugAuth.CredentialStore`\nbehaviour, which effectively narrows down to one function: `get_user_data/1`.\nThe returned value must be anything but `nil` for the authentication to be\nconsidered successful and for the data to appear in connection assigns.\n\nIn order to use a custom module, a `store` option must be passed along with\nother Plug initialization parameters, as shown in the example above.\n\n## Access control\nPlugAuth currently provides role-based access control, which can be performed after authentication. You would use it like this\n\n```elixir\nplug PlugAuth.Authentication.Basic, realm: \"Secret\"\nplug PlugAuth.Access.Role, roles: [:admin, :developer]\n```\n\nIn the example above HTTP basic authentication is used, but you could use any other authentication plug as well. The roles parameter specifies which user roles are granted access. On authentication failure the HTTP status code 403 will be sent, together with an error message which can be set using the error parameter (just like in the Authentication examples).\n\nThe role of the currently authenticated user, is read from the :authenticated_user assign of the connection. If when adding credentials you passed a map or structure as the user data and this map has a :role, \"role\", :roles or \"roles\" key, then everything will work automatically. If your user data is not a map or a structure, or it does not contain the role key, you can implemented the ```PlugAuth.Access.RolesAdapter``` protocol instead.\n\n## Plugs Composition Example\n\nFor situations when you need both Basic Auth and Token Auth subsequently, you\nare free to compose them into a single plug.\nTo differentiate between the authentication levels, you should parametrize\nboth of the plugs with `assign_key`. This designates the key name that will be used\nin `Plug.Conn` assigns to store the data obtained from `CredentialStore`.\n\n```elixir\ndefmodule BasicWithTokenPlug do\n  use Plug.Builder\n  import Plug.Conn\n\n  plug PlugAuth.Authentication.Basic,\n    realm: \"Secret\",\n    assign_key: :basic_user\n\n  plug PlugAuth.Authentication.Token,\n    source: :header,\n    param: \"x-auth-token\",\n    error: ~s'{\"error\":\"authentication required\"}',\n    assign_key: :token_user\n  plug :index\n\n  defp index(conn, _opts), do: send_resp(conn, 200, \"Authorized\")\nend\n```\n\n## Redirect Example\nYou may wish to redirect unauthorized users to a login page. This can be achieved by passing a function to the error parameter of a plug. This works for `PlugAuth.Authentication`'s `Basic` and `Token` as well as `PlugAuth.Access.Role`. The function cannot be private. The following example demonstrates a simple implementation of this:\n\n```elixir\ndefmodule RedirectPlug do\n  use Plug.Builder\n  import Plug.Conn\n\n  plug PlugAuth.Authentication.Basic,\n    realm: \"Secret\",\n    error: \u0026RedirectPlug.unauthorized/1\n  plug :index\n\n  @doc \"\"\"\n    Redirect an unauthorized user to the login page.\n  \"\"\"\n  def unauthorized(conn), do: conn |\u003e redirect(to: \"/login\")\n\n  defp index(conn, _opts), do: send_resp(conn, 200, \"Authorized\")\nend\n\n```\n\n## License\nCopyright (c) 2014, Bitgamma OÜ \u003copensource@bitgamma.com\u003e\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\nANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\nACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\nOR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbitgamma%2Fplug_auth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbitgamma%2Fplug_auth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbitgamma%2Fplug_auth/lists"}