{"id":13393265,"url":"https://github.com/smpallen99/coherence","last_synced_at":"2025-05-14T09:07:53.684Z","repository":{"id":9586353,"uuid":"62584632","full_name":"smpallen99/coherence","owner":"smpallen99","description":"Coherence is a full featured, configurable authentication system for Phoenix","archived":false,"fork":false,"pushed_at":"2024-08-20T16:24:14.000Z","size":1106,"stargazers_count":1265,"open_issues_count":75,"forks_count":223,"subscribers_count":28,"default_branch":"master","last_synced_at":"2025-05-10T20:34:08.445Z","etag":null,"topics":["authentication","elixir","hex","package","phoenix-framework"],"latest_commit_sha":null,"homepage":null,"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/smpallen99.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2016-07-04T19:47:25.000Z","updated_at":"2025-04-17T05:58:17.000Z","dependencies_parsed_at":"2023-01-13T15:26:59.528Z","dependency_job_id":"b9953f34-e01f-4e5b-be5b-58260aa8d979","html_url":"https://github.com/smpallen99/coherence","commit_stats":{"total_commits":379,"total_committers":74,"mean_commits":5.121621621621622,"dds":0.4195250659630607,"last_synced_commit":"ede75598de6b01ce896d6ec67f0aeac6047ddbd9"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smpallen99%2Fcoherence","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smpallen99%2Fcoherence/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smpallen99%2Fcoherence/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/smpallen99%2Fcoherence/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/smpallen99","download_url":"https://codeload.github.com/smpallen99/coherence/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254110374,"owners_count":22016391,"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":["authentication","elixir","hex","package","phoenix-framework"],"created_at":"2024-07-30T17:00:48.049Z","updated_at":"2025-05-14T09:07:48.675Z","avatar_url":"https://github.com/smpallen99.png","language":"Elixir","funding_links":[],"categories":["Authentication","Elixir"],"sub_categories":[],"readme":"# Coherence\n\n[![Build Status](https://travis-ci.org/smpallen99/coherence.svg?branch=master)](https://travis-ci.org/smpallen99/coherence) [![Hex Version][hex-img]][hex] [![License][license-img]][license]\n\n[hex-img]: https://img.shields.io/hexpm/v/coherence.svg\n[hex]: https://hex.pm/packages/coherence\n[license-img]: http://img.shields.io/badge/license-MIT-brightgreen.svg\n[license]: http://opensource.org/licenses/MIT\n\nCheckout the [Coherence Demo Project](https://github.com/smpallen99/coherence_demo) to see an example project using Coherence.\n\nCoherence is a full featured, configurable authentication system for Phoenix, with the following modules:\n\n* [Database Authenticatable](#authenticatable): handles hashing and storing an encrypted password in the database.\n* [Invitable](#invitable): sends invites to new users with a sign-up link, allowing the user to create their account with their own password.\n* [Registerable](#registerable): allows anonymous users to register a users email address and password.\n* [Confirmable](#confirmable): new accounts require clicking a link in a confirmation email.\n* [Recoverable](#recoverable): provides a link to generate a password reset link with token expiry.\n* [Trackable](#trackable): saves login statistics like login counts, timestamps, and IP address for each user.\n* [Lockable](#lockable): locks an account when a specified number of failed sign-in attempts has been exceeded.\n* [Unlockable With Token](#unlockable-with-token): provides a link to send yourself an unlock email.\n* [Rememberable](#remember-me): provides persistent login with 'Remember me?' check box on login page.\n\nCoherence provides flexibility by adding namespaced templates and views for only the options specified by the `mix coh.install` command. This boiler plate code is added to your `lib/my_project/web/templates/coherence` and `lib/my_project/web/views/coherence` directories.\n\nOnce the boilerplate has been generated, you are free to customize the source as required.\n\nAs well, a `lib/my_project/web/coherence_web.ex` is added. Migrations are also generated to add the required database fields.\n\nSee the [Docs](https://hexdocs.pm/coherence/Coherence.html) and [Wiki](https://github.com/smpallen99/coherence/wiki) for more information.\n\n## Installation\n\n  1. Add coherence to your list of dependencies in `mix.exs`:\n\n      ```elixir\n      def deps do\n        [{:coherence, \"~\u003e 0.8\"}]\n      end\n      ```\n\n  2. Ensure coherence is started before your application:\n\n      ```elixir\n      def application do\n        extra_applications: [..., :coherence]]\n      end\n      ```\n\n## Upgrading\n\nAfter upgrading a Coherence version, you should generate the boilerplate files. To assist this process, use the `--reinstall` option.\n\nThis option uses your project's existing coherence config and runs the the installer with the same options.\n\n```shell\nmix coh.install --reinstall\n```\n\nRun a `git diff` to review the updated files. If you had updated any of the boilerplate files, you may need to manually integrate the changes into the newly generated files.\n\nRun `mix help coh.install` for more information.\n\n## Phoenix \u0026 Phx Project Structure\n\nCoherence supports projects created with the older `mix phoenix.new` and the newer `mix phx.new` commands. Separate versions of the mix tasks exist for each project structure.\n\nFor projects created with `mix phx.new`, use the following mix tasks:\n\n* `coh.install`\n* `coh.clean`\n\nFor projects created with `mix phx.new --umbrella`, ensure you are in the app directory and use the following options for the install:\n* `cd apps/my_project`\n* `coh.install --web-module MyProjectWeb --web-path ../my_project_web/lib/my_project_web`\n\n## Getting Started\n\nFirst, decide which modules you would like to use for your project. For the following example we are going to use a full install except for the confirmable option.\n\nRun the installer\n\n```bash\n$ mix coh.install --full-invitable\n```\n\nThis will:\n\n* add the coherence configuration to the end of your `config/config.exs` file.\n* add a new User model if one does not already exist\n* add migration files\n  * timestamp_add_coherence_to_user.exs if the User model already exists\n  * timestamp_create_coherence_user.exs if the User model does not exist\n  * timestamp_create_coherence_invitable.exs\n* add view files lib/my_project/web/views/coherence/\n* add template files to lib/my_project/web/templates/coherence\n* add email files to lib/my_project/web/emails/coherence\n* add lib/my_project/web/coherence_web.ex file\n* add lib/my_project/web/coherence_messages.ex file\n\nYou should review your `config/config.exs` as there are a couple items you will need to customize like email address and mail api_key. If you don't edit the email_from value to something different than its default, emails may not be sent.\n\nSee [Installer](#installer) for more install options.\n\nYou will need to update a few files manually.\n\n```elixir\n# lib/my_project_web/router.ex\n\ndefmodule MyProjectWeb.Router do\n  use MyProjectWeb, :router\n  use Coherence.Router         # Add this\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 Coherence.Authentication.Session  # Add this\n  end\n\n  # Add this block\n  pipeline :protected 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 Coherence.Authentication.Session, protected: true\n  end\n\n  # Add this block\n  scope \"/\" do\n    pipe_through :browser\n    coherence_routes()\n  end\n\n  # Add this block\n  scope \"/\" do\n    pipe_through :protected\n    coherence_routes :protected\n  end\n\n  scope \"/\", MyProjectWeb do\n    pipe_through :browser\n\n    get \"/\", PageController, :index\n    # add public resources below\n  end\n\n  scope \"/\", MyProjectWeb do\n    pipe_through :protected\n\n    # add protected resources below\n    resources \"/privates\", MyProjectWeb.PrivateController\n  end\nend\n```\n**Important**: Note the name-spacing above. Unless you generate coherence controllers, ensure that the scopes, `scope \"/\" do`, do not include your projects' scope here. If so, the coherence routes will not work!\n\nIf the installer created a user schema (one did not already exist), there is nothing you need to do with that generated file. Otherwise, update your existing schema (assuming its `Accounts.User` like this:\n\n```elixir\n# lib/my_project/accounts/user.ex\n\ndefmodule MyProject.Accounts.User do\n  use Ecto.Schema\n  use Coherence.Schema                                    # Add this\n\n  schema \"users\" do\n    field :name, :string\n    field :email, :string\n    coherence_schema()                                    # Add this\n\n    timestamps()\n  end\n\n  def changeset(model, params \\\\ %{}) do\n    model\n    |\u003e cast(params, [:name, :email] ++ coherence_fields)  # Add this\n    |\u003e validate_required([:name, :email])\n    |\u003e validate_format(:email, ~r/@/)\n    |\u003e validate_coherence(params)                         # Add this\n  end\n\n  def changeset(model, params, :password) do\n    model\n    |\u003e cast(params, ~w(password password_confirmation reset_password_token reset_password_sent_at))\n    |\u003e validate_coherence_password_reset(params)\n  end\nend\n```\n\nAn alternative approach is add the authentication plugs to individual controllers that require authentication. You will want to use this approach if you require authentication for a subset of actions in a controller.\n\nFor example, lets say you want to show a list of products for everyone visiting the site, but only want authenticated users to be able to create, update, and delete products. You could do the following:\n\nEnsure the following is in your `lib/my_project_web/router.ex` file:\n\n```elixir\nscope \"/\", MyProjectWeb do\n  pipe_through :browser\n  resources \"/products\", ProductController\nend\n```\n\nIn your product controller add the following:\n\n```elixir\ndefmodule MyProjectWeb.ProductController do\n  use MyProjectWeb, :controller\n\n  plug Coherence.Authentication.Session, [protected: true] when action != :index\n\n  # ...\nend\n```\n\n## Default Configuration\n\n```elixir\n{:require_current_password, true}, # Current password is required when updating new password.\n{:reset_token_expire_days, 2},\n{:confirmation_token_expire_days, 5},\n{:allow_unconfirmed_access_for, 0},\n{:max_failed_login_attempts, 5},\n{:unlock_timeout_minutes, 20},\n{:unlock_token_expire_minutes, 5},\n{:rememberable_cookie_expire_hours, 2*24},\n{:forwarded_invitation_fields, [:email, :name]}\n{:allow_silent_password_recovery_for_unknown_user, false},\n{:password_hashing_alg, Comeonin.Bcrypt}\n```\n\nYou can override this default configs. For example: you can add the following codes inside `config/config.exs`\n\n```elixir\nconfig :coherence,\n  require_current_password: false,\n  max_failed_login_attempts: 3\n```\n\n## Custom registration and sessions routes\n\nCoherence supports custom routes for registration and login. These configurations can be set globally or scoped.\n\nWhich routes can be custom?\n\n```\n%{\n  registrations_new:  \"/registrations/new\",\n  registrations:      \"/registrations\",\n  passwords:          \"/passwords\",\n  confirmations:      \"/confirmations\",\n  unlocks:            \"/unlocks\",\n  invitations:        \"/invitations\",\n  invitations_create: \"/invitations/create\",\n  invitations_resend: \"/invitations/:id/resend\",\n  sessions:           \"/sessions\",\n  registrations_edit: \"/registrations/edit\"\n}\n```\n\nTo set them globally add the following to you configuration:\n\n\n\n```elixir\nconfig :coherence,\n  default_routes: %{\n    registrations_edit: \"/accounts/edit\", ...},\n```\n\nTo set them scoped for each mode (protected, public, etc..):\n\n```elixir\nscope \"/\" do\n  pipe_through :protected\n  coherence_routes :protected, [\n    custom_routes: %{registratons_edit: \"/accounts/edit\", ...}\n  ]\nend\n```\n\n## Phoenix Channel Authentication\n\nCoherence supports channel authentication using `Phoenix.Token`. To enable channel authentication do the following:\n\nAdd the following option to coherence configuration.\n\n```elixir\nconfig :coherence,\n  user_token: true\n```\n\nUpdate your socket module:\n\n```elixir\ndefmodule MyProjectWeb.UserSocket do\n  use Phoenix.Socket\n\n  def connect(%{\"token\" =\u003e token}, socket) do\n    case Coherence.verify_user_token(socket, token, \u0026assign/3) do\n      {:error, _} -\u003e :error\n      {:ok, socket} -\u003e {:ok, socket}\n    end\n  end\nend\n```\n\n## Localization with Gettext\n\nCoherence supports `Gettext` for all User facing messages. Your project's `Gettext` module is used by default.\n\nAll Coherence messages use `dgettext` with the `\"coherence\"` domain. This means that after you run `mix gettext.extract`, you will see `coherence.pot` files generated. Running `mix gettext.merge priv/gettext` will generate the corresponding `coherence.po` files.\n\nCoherence does not come with pre-translated `.po` files. We figure that you will want to tweak the Coherence language to suite your application.\n\nAll files added to your project with the Coherence generators include a `import MyProjectWeb.Gettext` with the `\"coherence\"` domain.\n\nThe other messages that Coherence uses internal are pulled from the `my_project_web/coherence_messages.ex` file that is generated with the `coh.install` mix task. You can edit this file and customize it as required.\n\nTo assist in upgrades to future releases of Coherence, the `MyProject.Coherence.Messages` module uses the `Coherence.Messages` behaviour which defines each message function. So, if you miss a message after upgrading, you will see a message during compile time.\n\n## Option Overview\n\n### Authenticatable\n\nHandles hashing and storing an encrypted password in the database.\n\nProvides `/sessions/new` and `/sessions/delete` routes for logging in and out with\nthe appropriate templates and view.\n\nThe following columns are added the `\u003ctimestamp\u003e_add_coherence_to_user.exs` migration:\n\n* :password_hash, :string - the encrypted password\n\n### Invitable\n\nHandles sending invites to new users with a sign-up link, allowing the user to create their account with their own password.\n\nProvides `/invitations/new` and `invitations/edit` routes for creating a new invitation and creating a new account from the invite email.\n\nThese routes can be configured to require login by using the `coherence_routes :private` macro in your router.exs file.\n\nInvitation token timeout will be added in the future.\n\nThe following table is created by the generated `\u003ctimestamp\u003e_create_coherence_invitable.exs` migration:\n\n```elixir\ncreate table(:invitations) do\n  add :name, :string\n  add :email, :string\n  add :token, :string\nend\n```\n\n### Registerable\n\nAllows anonymous users to register a users email address and password.\n\nProvides `/registrations/new`, `create`, `edit`, `update`, `show`, and `delete` routes for managing registrations.\n\nAdds the following:\n\n* `Register New Account` to the log-in page.\n* `Link to account page on layout helpers`\n* Show page with `edit` and `delete` links\n* `edit` page\n\nIt is recommended that the :confirmable option is used with :registerable to\nensure a valid email address is captured.\n\n### Confirmable\n\nRequires a new account be confirmed. During registration, a confirmation token is generated and sent to the registering email. This link must be clicked before the user can sign-in.\n\nProvides `edit` action for the `/confirmations` route.\n\nThe confirmation token expiry default of 5 days can be changed with the `:confirmation_token_expire_days` config entry.\n\n### Recoverable\n\nAllows users to reset their password using an expiring token send by email.\n\nProvides `new`, `create`, `edit`, `update` actions for the `/passwords` route.\n\nAdds a \"Forgot your password?\" link to the log-in form. When clicked, the user provides their email address and if found, sends a reset password instructions email with a reset link.\n\nThe expiry timeout can be changed with the `:reset_token_expire_days` config entry.\n\nBy default, providing an unknown email address will result in a form error. If you want to prevent that and display a confirmation message even if the email isn’t found, set the `:allow_silent_password_recovery_for_unknown_user` to `true`.\n\n### Trackable\n\nSaves login statistics like login counts, timestamps, and IP address for each user.\n\nAdds the following database field to your User model with the generated migration:\n\n```elixir\nadd :sign_in_count, :integer, default: 0  # how many times the user has logged in\nadd :current_sign_in_at, :datetime        # the current login timestamp\nadd :last_sign_in_at, :datetime           # the timestamp of the previous login\nadd :current_sign_in_ip, :string          # the current login IP adddress\nadd :last_sign_in_ip, :string             # the IP address of the previous login\n```\n\n### Lockable\n\nLocks an account when a specified number of failed sign-in attempts has been exceeded.\n\nThe following defaults can be changed with the following config entries:\n\n* `:unlock_timeout_minutes`\n* `:max_failed_login_attempts`\n\nAdds the following database field to your User model with the generated migration:\n\n```elixir\nadd :failed_attempts, :integer, default: 0\nadd :unlock_token, :string\nadd :locked_at, :datetime\n```\n\n### Unlockable with Token\n\nProvides a link to send yourself an unlock email. When the user clicks the link, the user is presented a form to enter their email address and password. If the token has not expired and the email and password are valid, a unlock email is sent to the user's email address with an expiring token.\n\nThe default expiry time can be changed with the `:unlock_token_expire_minutes` config entry.\n\n### Remember Me\n\nThe `rememberable` option provides persistent login when the 'Remember Me?' box is checked during login.\n\nWith this feature, you will automatically be logged in from the same browser when your current login session dies using a configurable expiring persistent cookie.\n\nFor security, both a token and series number stored in the cookie on initial login. Each new creates a new token, but preserves the series number, providing protection against fraud. As well, both the token and series numbers are hashed before saving them to the database, providing protection if the database is compromised.\n\nThe following defaults can be changed with the following config entries:\n\n* :rememberable_cookie_expire_hours (2\\*24)\n* :login_cookie                     (\"coherence_login\")\n\nThe following table is created by the generated `\u003ctimestamp\u003e_create_coherence_rememberable.exs` migration:\n\n```elixir\ncreate table(:rememberables) do\n  add :series_hash, :string\n  add :token_hash, :string\n  add :token_created_at, :datetime\n  add :user_id, references(:users, on_delete: :delete_all)\n\n  timestamps\nend\n\ncreate index(:rememberables, [:user_id])\ncreate index(:rememberables, [:series_hash])\ncreate index(:rememberables, [:token_hash])\ncreate unique_index(:rememberables, [:user_id, :series_hash, :token_hash])\n```\n\nThe `--rememberable` install option is not provided in any of the installer group options. You must provide the `--rememberable` option to install the migration and its support.\n\n### User Active Field\n\nThe `--user-active-field` option can be given to the installer to support inactive users. When a user is set as inactive, they will not be able to login.\n\nUsing this option adds a `active` field to the user schema with a default of `true`.\n\n## Mix Tasks\n\n### Installer\n\nThe following examples illustrate various configuration scenarios for the install mix task:\n\n```bash\n# Install with only the `authenticatable` option\n$ mix coh.install\n\n# Install all the options except `confirmable` and `invitable`\n$ mix coh.install --full\n\n# Install all the options except `invitable`\n$ mix coh.install --full-confirmable\n\n# Install all the options except `confirmable`\n$ mix coh.install --full-invitable\n\n# Install the `full` options except `lockable` and `trackable`\n$ mix coh.install --full --no-lockable --no-trackable\n```\n\nAnd some reinstall examples:\n\n```bash\n# Reinstall with defaults (--silent --no-migrations --no-config --confirm-once)\n$ mix coh.install --reinstall\n\n# Confirm to overwrite files, show instructions, and generate migrations\n$ mix coh.install --reinstall --no-confirm-once --with-migrations\n```\n\nRun `$ mix help coh.install` for more information.\n\n### Clean\n\nThe following examples illustrate how to remove the files created by the installer:\n\n```bash\n# Clean all the installed files\n$ mix coh.clean --all\n\n# Clean only the installed view and template files\n$ mix coh.clean --views --templates\n\n# Clean all but the models\n$ mix coh.clean --all --no-models\n\n# Prompt once to confirm the removal\n$ mix coh.clean --all --confirm-once\n```\n\nAfter installation, if you later want to remove one more options, here are a couple examples:\n\n```bash\n# Clean one option\n$ mix coh.clean --options=recoverable\n\n# Clean several options without confirmation\n$ mix coh.clean --no-confirm --options=\"recoverable unlockable-with-token\"\n\n# Test the uninstaller without removing files\n$ mix coh.clean --dry-run --options=\"recoverable unlockable-with-token\"\n```\n\n## Customization\n\nThe `coh.install` mix task generates a bunch of boiler plate code so you can easily customize the views, templates, and mailer.\n\nAlso, checkout the Coherence.Config module for a list of config items you can use to tune the behaviour of Coherence.\n\n### Custom Controllers\n\nBy default, controller boilerplate is not generated. To add controllers, use the controller generators.\n\n* For phx projects, use the `mix coh.gen.controllers` task.\n\nThe generated controllers are named `MyProjectWeb.Coherence.SessionController` as an example. Generated controllers are located in `lib/my_project_web/controllers/coherence/`\n\nIf the controllers are generated, you will need to change your router to use the new names. For example:\n\n```elixir\n# lib/my_project_web/router.ex\n\ndefmodule MyProjectWeb.Router do\n  use MyProjectWeb, :router\n  use Coherence.Router\n\n  # ...\n\n  scope \"/\", MyProjectWeb do   # note the addition of MyProjectWeb\n    pipe_through :public\n    coherence_routes()\n  end\n\n  scope \"/\", MyProjectWeb do   # note the addition of MyProjectWeb\n    pipe_through :browser\n    coherence_routes :protected\n  end\n\n  # ...\nend\n```\n\nAs of Coherence v0.6.0, the generated controller modules have very little code. All the controller actions and helper functions are included with a `use xxxControllerBase` call.\n\nTo change an action, simply define the appropriate function and add your own implementation. You may want to copy over the implementation found in your projects `deps/coherence/lib/coherence/controllers/xxx_controller_base.ex` file as a starting point and customize it as needed.\n\nAlternatively, if can create the action, handle some specify behavior and call `super(conn, params)` so invoke the default action. Depending on your customization, this may be the best approach since its easier to see how changes when upgrading to new versions of Coherence.\n\n### Customizing Routes\n\nBy default, Coherence assumes you want all available routes for the `opts` you've configured. However, you can specify which routes should be available by modifying your configuration.\n\nFor example, if you want all of the routes for `authenticatable`, but only the `new` and `create` actions from `registerable`:\n\n```elixir\n# config/config.exs\nconfig :coherence,\n  # ...\n  opts: [:authenticatable, registerable: [:new, :create]]\n```\n\n### Customizing Redirections\n\nMany of the controller actions redirect the user after create and update actions. These redirections can be customized by adding function call backs in the `lib/my_project_web/controllers/coherence/redirect.ex` module that is generated by the `mix coh.install` task.\n\nFor example, to have the user redirected to the login screen after logging out at the following:\n\n```elixir\ndefmodule Coherence.Redirects do\n  use Redirects\n  import MyProjectWeb.Router.Helpers\n\n  # override the log out action back to the log in page\n  def session_delete(conn, _), do: redirect(conn, session_path(conn, :new))\nend\n```\n\nSee the documentation for further details.\n\n### Customizing Responders\n\nTo customize how application responds to html or json format, you can override methods in the `lib/my_project_web/controllers/coherence/responders/html.ex` or `lib/my_project_web/controllers/coherence/responders/json.ex`.\n\n### Customizing layout\n\nBy default coherence uses its own layout which is installed to `lib/my_project_web/templates/coherence/layout/app.html.eex`.\n\nIf you want to customize coherence controllers layout, you can follow different approaches:\n\n* Edit the generated layout at `lib/my_project_web/templates/coherence/layout/app.html.eex`.\n* Set `:layout` in your config file. e.g. `config :coherence, :layout, {MyProjectWeb.LayoutView, :app}`\n* Install coherence controllers to application and edit them, to use layout module different from `Coherence.LayoutView`\n* And the last solution is to use `plug :put_layout` in your `lib/my_project_web/router.ex` file. For example:\n\n```elixir\ndefmodule MyProjectWeb.Router do\n  # ...\n  pipeline :coherence do\n    plug :put_layout, {MyProjectWeb.LayoutView, :app}\n  end\n  # ...\n  scope \"/\" do\n    pipe_through [:protected, :coherence]\n    coherence_routes :protected\n  end\n  #...\nend\n```\n\n## Customizing User Changeset\n\nThe User model changeset used by Coherence can be customized for each Coherence controller. To customize the changeset, set the `changeset` config option.\n\nFor example, the following defines a changeset/3 function in your user model:\n\n```elixir\n# config/config.exs\nconfig :coherence,\n  # ...\n  changeset: {MyProject.User, :changeset}\n```\n\nNow add a new `changeset/3` function to the user model. The following example defines a custom changeset for the registration controller:\n\n```elixir\n# lib/coherence/coherence/user.ex\ndefmodule CoherenceDemo.User do\n  use Ecto.Schema\n  use Coherence.Schema\n\n  # ...\n\n  def changeset(model, params \\\\ %{}) do\n    model\n    |\u003e cast(params, [:name, :email] ++ coherence_fields)\n    |\u003e validate_required([:name, :email])\n    |\u003e validate_format(:email, ~r/@/)\n    |\u003e unique_constraint(:email)\n    |\u003e validate_coherence(params)\n  end\n  def changeset(model, params, :registration) do\n    # custom changeset  for registration controller\n    model\n    |\u003e cast(params, [:name, :email] ++ coherence_fields)\n    |\u003e validate_required([:name, :email])\n    |\u003e validate_format(:email, ~r/@/)\n    |\u003e unique_constraint(:email)\n    |\u003e validate_coherence(params)\n  end\n  def changeset(model, params, _which) do\n    # use the default changeset for all other coherence controllers\n    changeset model, params\n  end\nend\n```\n\nWhen a custom changeset is configured, the changeset function is called with an atom indicating the controller calling the changeset, allowing you to match on specific controllers.\n\nThe list of controller actions are:\n\n* :confirmation\n* :invitation\n* :password\n* :registration\n* :session\n* :unlock\n\n## Customizing Password Hashing Algorithm\n\nCoherence uses the `Bcrypt` algorithm by default for hashing passwords. However, with the update to Comeonin 4.0, you can now change the hashing algorithm.\n\nComeonin currently supports the following 3 algorithms:\n\n* [Argon2](https://github.com/riverrun/argon2_elixir)\n* [Bcrypt](https://github.com/riverrun/bcrypt_elixir)\n* [Pbkdf2](https://github.com/riverrun/pbkdf2_elixir)\n\n### Change the Hashing Algorithm in an Existing Project\n\nTo change the default in an existing project (to Argon2 for example), make the following 2 changes:\n\n* Edit your `config/config.exs` file add/change the following line:\n\n```elixir\n# config/config.exs\nconfig :coherence,\n  # ...\n  password_hashing_alg: Comeonin.Argon2,\n  # ...\n```\n\n* add the dependency to `mix.exs`\n\n```elixir\n  # mix.exs\n  defp deps do\n    [\n      # ...\n      {:argon2_elixir, \"~\u003e 1.3\"}\n    ]\n  end\n```\n\n### Change the Hashing Algorithm in an Existing Project\n\nTo install Coherence in a new project with the `Pbkdf2` hashing algorithm (with the --full option for example):\n\n```bash\n# mix coh.install --full --password-hashing-alg=Comeonin.Argon2\n```\n\nand add the dependency\n\n```elixir\n  # mix.exs\n  defp deps do\n    [\n      # ...\n      {:pbkdf2_elixir, \"~\u003e 0.12\"}\n    ]\n  end\n```\n\n### Speed up Tests and Database Seeding of Users\n\nThe default hashing algorithms are setup for production use. They are very slow by design which can cause very slow tests and database seeding in the dev and test environments. To speed this up, you can add the following to you `config/dev.exs` and/or `config/test.exs` configuration.\n\nHowever, *DON'T  USE THESE SETTINGS IN PRODUCTION*\n\n```elixir\n# config/test.exs\nconfig :argon2_elixir,\n  t_cost: 1,\n  m_cost: 8\nconfig :bcrypt_elixir, log_rounds: 4\nconfig :pbkdf2_elixir, rounds: 1\n```\n\nNote: Only configure the algorithm you have configured!\n\n## Accessing the Currently Logged In User\n\nDuring login, a current version of the user model is cashed in the credential store. During each authentication request, the user model is fetched from the credential store and placed in conn.assigns[:current_user] to avoid a database fetch on each request.\n\nYou can access the current user's name in a template like this:\n\n```elixir\n\u003c%= Coherence.current_user_name(@conn) %\u003e\n```\n\nAny of the user model's available data can be accessed this way.\n\n## Updating the User Model\n\nIf the user model is changed after login, a call to `update_login` must be done to update the credential store. For example, in your controller update function, call:\n\n```elixir\nCoherence.update_user_login(conn, user)\n```\n\nto update the credential store.\n\nThis is not needed for registration update page.\n\n## Configuring the Swoosh Email Adapter\n\nThe following configuration must be setup to send emails:\n\n```elixir\nconfig :coherence,\n  email_from_name: \"Some Name\",\n  email_from_email: \"myname@domain.com\"\n\nconfig :coherence, CoherenceDemoWeb.Coherence.Mailer,\n  adapter: Swoosh.Adapters.Sendgrid,\n  api_key: \"SENDGRID_API_KEY\"\n```\n\nYou may want to configure the email system to use system environment variables.\n\n```elixir\nconfig :coherence,\n  email_from_name: {:system, \"NAME\"},\n  email_from_email: {:system, \"EMAIL\"}\n\nconfig :coherence, CoherenceDemoWeb.Coherence.Mailer,\n  api_key: {:system, \"SENDGRID_API_KEY\"}\n```\n\n## Permitted Attributes\n\nFor security, Coherence restricts what fields of a schema can be created or\nupdated with several configurable permitted attributes settings. When installing\na new project these settings are generated in the `:coherence` Config block.\n\nIn the case of an upgrade, the following values will be used when the configuration\nis not found:\n\n| Configuration Field | Defaults |\n| --- | --- |\n| `:registration_permitted_attributes` | [\"email\",\"name\",\"password\", \"current_password\", \"password_confirmation\"] |\n| `:invitation_permitted_attributes` | [\"name\",\"email\"] |\n| `:password_reset_permitted_attributes` | [\"reset_password_token\",\"password\", \"password_confirmation\"] |\n| `:session_permitted_attributes` | [\"remember\",\"email\",\"password\"] |\n\n## Authentication\n\nCurrently Coherence supports three modes of authentication including HTTP Basic, Session, and Token authentication.\n\nFor HTTP Basic and Token authentication, you will need to add the credentials into the Credential Store. This is not required for Session or IpAddress Authentication.\n\nIpAddress authentication is a good solution for server to server rest APIs.\n\n### Add HTTP Basic Credentials Example\n\n```elixir\ncreds = Coherence.Authentication.Basic.encode_credentials(\"Admin\", \"SecretPass\")\nCoherence.CredentialStore.Server.put_credentials(creds, %{id: \"USER_ID_HERE\", role: :admin})\n```\n\n### Add Token Credentials Example\n\n```elixir\ntoken = Coherence.Authentication.Token.generate_token\nCoherence.CredentialStore.Server.put_credentials(token, %{id: \"USER_ID_HERE\", role: :admin})\n```\n\n### Add IP Credentials Example\n\n```elixir\nCoherence.CredentialStore.Server.put_credentials({127,0,0,1}, %{id: \"USER_ID_HERE\", role: :admin})\n```\n\nIpAddress authentication does not require this step. Its optional. If the user_data\nis not found in the credential store, the conn.assigns will not be set.\n\nTo add authentication, use on of the following three:\n\n### HTTP Basic Plug Example\n\n```elixir\nplug Coherence.Authentication.Basic, realm: \"Secret\"\n```\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 Plug Example\n\n```elixir\nplug Coherence.Authentication.Token, source: :params, param: \"auth_token\", error: ~s'{\"error\":\"authentication required\"}'\n```\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### Session Plug Example\n\n```elixir\nplug Coherence.Authentication.Session, cookie_expire: 10*60*60, login: \u0026MyController.login/1, assigns_key: :authenticated_user\n```\n\nThe `:cookie_expire` value the expire time in seconds. The `:login` is a fun that will be passed `conn` if the user is not logged in. Use the `:assigns_key` to change the default `:current_user` value.\n\nNote that if you provide a login callback, that you must return `halt conn` a the end of the function.\n\n### IP Address Plug Example\n\n```elixir\nplug Coherence.Authentication.IpAddress, allow: ~w(127.0.0.1 192.168.1.0/24)\nplug Coherence.Authentication.IpAddress, allow: ~w(0.0.0.0/0), deny: ~w(127.0.0.1)\n```\n\nThe first example will allow local host and any ip address in the subnet 192.168.1.0/255.255.255.0\n\nThe second example allows any ip except for localhost.\n\n## Authorization\n\nCoherence is a user management and authentication solution. Support for authorization (access control) can be achieved using another package like [Canary](https://github.com/cpjk/canary).\n\nFor an example of using [Canary](https://github.com/cpjk/canary) with Coherence, please visit the [CoherenceDemo canary branch](https://github.com/smpallen99/coherence_demo/tree/canary).\n\n## Contributing\n\nWe appreciate any contribution to Coherence. Check our [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md) and [CONTRIBUTING.md](CONTRIBUTING.md) guides for more information. We usually keep a list of features and bugs [in the issue tracker][1].\n\n## References\n\n* Detailed Example [Coherence Demo](https://github.com/smpallen99/coherence_demo)\n* [Docs](https://hexdocs.pm/coherence/)\n\n  [1]: https://github.com/smpallen99/coherence/issues\n\n## License\n\n`coherence` is Copyright (c) 2016-2018 E-MetroTel\n\nThe source is released under the MIT License.\n\nCheck [LICENSE](LICENSE) for more information.\n\nMuch of the authentication plugs code was taken from [PlugAuth](https://github.com/bitgamma/plug_auth), Copyright (c) 2014, Bitgamma OÜ \u003copensource@bitgamma.com\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmpallen99%2Fcoherence","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsmpallen99%2Fcoherence","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsmpallen99%2Fcoherence/lists"}