{"id":13507402,"url":"https://github.com/BlakeWilliams/doorman","last_synced_at":"2025-03-30T08:30:30.320Z","repository":{"id":57491154,"uuid":"60926165","full_name":"BlakeWilliams/doorman","owner":"BlakeWilliams","description":"Tools to make Plug, and Phoenix authentication simple and flexible.","archived":false,"fork":false,"pushed_at":"2022-04-11T20:34:06.000Z","size":62,"stargazers_count":120,"open_issues_count":2,"forks_count":12,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-29T01:41:23.504Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","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/BlakeWilliams.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":"2016-06-11T20:19:23.000Z","updated_at":"2024-06-07T22:08:34.000Z","dependencies_parsed_at":"2022-08-30T04:00:23.600Z","dependency_job_id":null,"html_url":"https://github.com/BlakeWilliams/doorman","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlakeWilliams%2Fdoorman","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlakeWilliams%2Fdoorman/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlakeWilliams%2Fdoorman/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlakeWilliams%2Fdoorman/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BlakeWilliams","download_url":"https://codeload.github.com/BlakeWilliams/doorman/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246258868,"owners_count":20748573,"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:33.011Z","updated_at":"2025-03-30T08:30:30.269Z","avatar_url":"https://github.com/BlakeWilliams.png","language":"Elixir","funding_links":[],"categories":["Authentication"],"sub_categories":[],"readme":"# Doorman\n\nModules and functions to make authentication with Plug/Phoenix and Ecto easy\nwithout tons of configuration or boxing users into rigid framework.\n\nThe primary goal of Doorman is to build an opinionated interface and easy to use\nAPI on top of flexible modules that can also be used directly.\n\nYou can find more in-depth [documentation here](https://hexdocs.pm/doorman/).\n\n## Installation\n\nAdd doorman to your dependencies in `mix.exs`.\n\n```elixir\ndef deps do\n  [{:doorman, \"~\u003e 0.6.2\"}]\nend\n```\n\nThen add the configuration to `config/config.exs`.\n\n```elixir\nconfig :doorman,\n  repo: MyApp.Repo,\n  secure_with: Doorman.Auth.Bcrypt,\n  user_module: MyApp.User\n```\n\n## Phoenix Quick Start\n\nFirst generate a user model with a `hashed_password` and `session_secret` field.\n\n```sh\n$ mix phoenix.gen.model User users email hashed_password session_secret\n```\n\nPlease note: we recommend using [citext] (or equivalent for non-postgres\ndatabases) for the email column so that your email is case insensitive.\n\n[citext]: https://www.postgresql.org/docs/9.1/static/citext.html\n\nNext, use `Doorman.Auth.Bcrypt` in your new `User` module and add a virtual\n`password` field. `hash_password/1` is used in the changeset to hash our\npassword and put it into the changeset as `hashed_password`.\n\n```elixir\ndefmodule MyApp.User do\n  use MyApp.Web, :model\n  import Doorman.Auth.Bcrypt, only: [hash_password: 1]\n\n  schema \"users\" do\n    field :email, :string\n    field :hashed_password, :string\n    field :password, :string, virtual: true\n    field :session_secret, :string\n\n    timestamps\n  end\n\n  def create_changeset(struct, params \\\\ %{}) do\n    struct\n    |\u003e cast(params, ~w(email password))\n    |\u003e hash_password\n  end\nend\n```\n\nFinally, we can add our plug so we can have access to `current_user` on\n`conn.assigns`. 99% of the time that means adding the `Doorman.Login.Session`\nplug to your `:browser` pipeline:\n\n```elixir\npipeline :browser do\n  # ...\n  plug Doorman.Login.Session\n  # ...\nend\n```\n\n### Creating Users\n\nTo create a user we can use the `MyApp.create_changeset/2` function we defined. Here we'll also add the `session_secret` to the user, which is only needed when creating an user or in case of compromised sessions.\n\n```elixir\ndefmodule MyApp.UserController do\n  use MyApp.Web, :controller\n  alias Doorman.Auth.Secret\n  alias MyApp.User\n\n  def new(conn, _params) do\n    changeset = User.create_changeset(%User{})\n    conn |\u003e render(\"new.html\", changeset: changeset)\n  end\n\n  def create(conn, %{\"user\" =\u003e user_params}) do\n    changeset = \n      %User{}\n      |\u003e User.create_changeset(user_params)\n      |\u003e Secret.put_session_secret()\n\n    case Repo.insert(changeset) do\n      {:ok, user} -\u003e\n        conn |\u003e redirect(to: \"/\")\n      {:error, changeset} -\u003e\n        conn |\u003e render(\"new.html\", changeset: changeset)\n    end\n  end\nend\n```\n\n### Logging in users\n\nTo login users we can use `Doorman.authenticate` and `Doorman.Login.Session.login/2`.\n\n```elixir\ndefmodule MyApp.SessionController do\n  use Myapp.Web, :controller\n  import Doorman.Login.Session, only: [login: 2]\n\n  def create(conn, %{\"session\" =\u003e %{\"email\" =\u003e email, \"password\" =\u003e password}}) do\n    if user = Doorman.authenticate(email, password) do\n      conn\n      |\u003e login(user) # Sets :user_id and :session_secret on conn's session\n      |\u003e put_flash(:notice, \"Successfully logged in\")\n      |\u003e redirect(to: \"/\")\n    else\n      conn\n      |\u003e put_flash(:error, \"No user found with the provided credentials\")\n      |\u003e render(\"new.html\")\n    end\n  end\nend\n```\n\n### Requiring Authentication\n\nTo require a user to be authenticated you can build a simple plug around\n`Doorman.logged_in?/1`.\n\n```elixir\ndefmodule MyApp.RequireLogin do\n  import Plug.Conn\n\n  def init(opts), do: opts\n\n  def call(conn, _opts) do\n    if Doorman.logged_in?(conn) do\n      conn\n    else\n      conn\n      |\u003e Phoenix.Controller.redirect(to: \"/login\")\n      |\u003e halt\n    end\n  end\nend\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBlakeWilliams%2Fdoorman","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FBlakeWilliams%2Fdoorman","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FBlakeWilliams%2Fdoorman/lists"}