{"id":13508067,"url":"https://github.com/manukall/phoenix_token_auth","last_synced_at":"2025-10-21T17:42:10.739Z","repository":{"id":28497307,"uuid":"32013650","full_name":"manukall/phoenix_token_auth","owner":"manukall","description":"Token authentication solution for Phoenix. Useful for APIs for e.g. single page apps.","archived":false,"fork":false,"pushed_at":"2016-08-16T11:36:47.000Z","size":144,"stargazers_count":163,"open_issues_count":14,"forks_count":37,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-09-30T10:46:10.761Z","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/manukall.png","metadata":{"files":{"readme":"README.md","changelog":"Changelog.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-03-11T11:17:25.000Z","updated_at":"2024-03-07T04:37:45.000Z","dependencies_parsed_at":"2022-09-26T18:20:48.312Z","dependency_job_id":null,"html_url":"https://github.com/manukall/phoenix_token_auth","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/manukall/phoenix_token_auth","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manukall%2Fphoenix_token_auth","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manukall%2Fphoenix_token_auth/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manukall%2Fphoenix_token_auth/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manukall%2Fphoenix_token_auth/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/manukall","download_url":"https://codeload.github.com/manukall/phoenix_token_auth/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/manukall%2Fphoenix_token_auth/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280304013,"owners_count":26307860,"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","status":"online","status_checked_at":"2025-10-21T02:00:06.614Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":[],"created_at":"2024-08-01T02:00:47.312Z","updated_at":"2025-10-21T17:42:10.688Z","avatar_url":"https://github.com/manukall.png","language":"Elixir","funding_links":[],"categories":["Framework Components"],"sub_categories":[],"readme":"[![ProjectTalk](http://www.projecttalk.io/images/gh_badge-3e578a9f437f841de7446bab9a49d103.svg?vsn=d)]\n(http://www.projecttalk.io/boards/manukall%2Fphoenix_token_auth?utm_campaign=gh-badge\u0026utm_medium=badge\u0026utm_source=github)\n\n# PhoenixTokenAuth is not really maintained. I do not recommend starting a new project with it.\nI'm not actively using this project at the moment. I also implmemented most of it when I just started with Elixir, so the code is not exactly great. If you want to use it, be prepared to fork the project and invest some work.\n\nPhoenixTokenAuth\n================\n\n\nAdds token authentication to Phoenix apps using Ecto.\n\nAn example app is available at https://github.com/manukall/phoenix_token_auth_react.\n\n## Setup\nYou need to have a user model with at least the following schema and callback:\n\n```elixir\ndefmodule MyApp.User do\n  use Ecto.Model\n\n  schema \"users\" do\n    field  :email,                       :string     # or :username\n    field  :hashed_password,             :string\n    field  :hashed_confirmation_token,   :string\n    field  :confirmed_at,                Ecto.DateTime\n    field  :hashed_password_reset_token, :string\n    field  :unconfirmed_email,           :string\n    field  :authentication_tokens,       {:array, :string}, default: []\n  end\n\n  @required_fields ~w(email)\n  @optional_fields ~w()\n\n  def changeset(model, params \\\\ :empty) do\n    model\n    |\u003e cast(params, @required_fields, @optional_fields)\n  end\n\nend\n```\n\nMake sure that you have uniqueness constraints on the email or username columns.\n\nThen add PhoenixTokenAuth to your Phoenix router:\n\n```elixir\ndefmodule MyApp.Router do\n  use Phoenix.Router\n  require PhoenixTokenAuth\n\n  pipeline :authenticated do\n    plug PhoenixTokenAuth.Plug\n  end\n\n  scope \"/api\" do\n    pipe_through :api\n\n    PhoenixTokenAuth.mount\n  end\n\n  scope \"/api\" do\n    pipe_through :authenticated\n    pipe_through :api\n\n    resources \"/messages\", MessagesController\n  end\nend\n```\nThis generates routes for sign-up and login and protects the messages resources from unauthenticated access.\n\nThe generated routes are:\n\nmethod | path | description\n-------|------|------------\nPOST | /api/users | sign up\nPOST | /api/users/:id/confirm | confirm account\nPOST | /api/session | login, will return a token as JSON\nDELETE |  /api/session | logout, invalidated the users current authentication token\nPOST | /api/password_resets | request a reset-password-email\nPOST | /api/password_resets/reset | reset a password\nGET  | /api/account               | get information about the current user. at the moment this includes only the email address\nPUT  | /api/account               | update the current users email or password\n\nIf you want to customize the routes, instead of\n```\n  scope \"/api\" do\n    pipe_through :api\n\n    PhoenixTokenAuth.mount\n  end\n```\nadd\n```\n  scope \"/api\" do\n    pipe_through :api\n\n    post  \"users\",                 PhoenixTokenAuth.Controllers.Users, :create\n    post  \"users/:id/confirm\",     PhoenixTokenAuth.Controllers.Users, :confirm\n    post  \"sessions\",              PhoenixTokenAuth.Controllers.Sessions, :create\n    delete  \"sessions\",            PhoenixTokenAuth.Controllers.Sessions, :delete\n    post  \"password_resets\",       PhoenixTokenAuth.Controllers.PasswordResets, :create\n    post  \"password_resets/reset\", PhoenixTokenAuth.Controllers.PasswordResets, :reset\n    get   \"account\",               PhoenixTokenAuth.Controllers.Account, :show\n    put   \"account\",               PhoenixTokenAuth.Controllers.Account, :update\n  end\n```\nAnd customize, change names/pipeline of the routes.\n\n\nInside the controller, the authenticated user is accessible inside the connections assigns:\n\n```elixir\ndef index(conn, _params) do\n  user_id = conn.assigns.authenticated_user.id\n  ...\nend\n```\n\nNow add configuration:\n```elixir\n# config/config.exs\nconfig :phoenix_token_auth,\n  user_model: Myapp.User,                                                              # ecto model used for authentication\n  repo: Myapp.Repo,                                                                    # ecto repo\n  crypto_provider: Comeonin.Bcrypt,                                                    # crypto provider for hashing passwords/tokens. see http://hexdocs.pm/comeonin/\n  token_validity_in_minutes: 7 * 24 * 60,                                              # minutes from login until a token expires\n  email_sender: \"myapp@example.com\",                                                   # sender address of emails sent by the app\n  emailing_module: MyApp.EmailConstructor,                                             # module implementing the `PhoenixTokenAuth.MailingBehaviour` for generating emails\n  mailgun_domain: \"example.com\",                                                       # domain of your mailgun account\n  mailgun_key: \"secret\",                                                               # secret key of your mailgun account\n  user_model_validator: {MyApp.Model, :user_validator}                                 # function receiving and returning the changeset for a user on registration and when updating the account. This is the place to run custom validations.\n```\n\nThe secret key for signing tokens must be provided for Joken to work. You must\nalso configure the JSON encoder for Joken to use. For using the Poison Encode function,\nwe provide the `PhoenixTokenAuth.PoisonHelper`. The secret_key should be set per\nenvironment and should not be committed to the repository.\n```elixir\n# config/config.exs\nconfig :joken,\n  json_module: PhoenixTokenAuth.PoisonHelper,\n  algorithm: :HS256 # Optional. defaults to :HS256\n```\n```elixir\n# config/[dev|test|prod].exs\nconfig :joken,\n  # Environment specific secret key for signing tokens.\n  # This should be a very long random string.\n  secret_key: \"very secret test key\",\n```\n\n## Usage\n\n### Signing up / Registering a new user\n* POST request to /api/users.\n* Body should be JSON encoded `{user: {email: \"user@example.com\", password: \"secret\"}}`.\n* This will send an email containing the confirmation token.\n\n### Signing up / Registering a new user with username\n* POST request to /api/users.\n* Body should be JSON encoded `{user: {username: \"usernameexample\", password: \"secret\"}}`.\n* The user will be registered and, comparing to the email implementation, already confirmed.\n\n### Confirming a user\n* POST request to /api/users/:id/confirm\n* Body should be JSON encoded `{confirmation_token: \"token form the email\"}`\n* This will mark the user as confirmed and return an authentication token as JSON: `{token: \"the_token\"}`.\n\n### Logging in\n* POST request to /api/sessions\n* Body should be JSON encoded `{email: \"user@example.com\", password: \"secret\"}`\n* Will return an authentication token as JSON: `{token: \"the_token\"}`\n\n### Logging in with username\n* POST request to /api/sessions\n* Body should be JSON encoded `{username: \"usernameexample\", password: \"secret\"}`\n* Will return an authentication token as JSON: `{access_token: \"the_token\", token_type: \"bearer\", id: \"recordid\"}`\n\n### Requesting a protected resource\n* Add a header with key `Authorization` and value `Bearer #{token}` to the request.\n* `#{token}` is the token from either account confirmation or logging in.\n\n### Logging out\n* DELETE request to /api/sessions\n* Just stop sending the `Authorization` header.\n\n### Resetting password\n* POST request to /api/password_resets\n* Body should be JSON encoded `{email: \"user@example.com\"}`\n* This will send an email as configured.\n* Once the reset token is received in the email, make a POST request to /api/password_resets/reset with body\n`{user_id: 123, password_reset_token: \"the_token_from_the_email\", password: \"the_new_password\"}`\n* This will change the users password and return an authentication token as JSON: `{token: \"the_token\"}`.\n\n### Change the current user's password\n* PUT request to /api/account\n* Body should be JSON encoded `{account: {password: \"newpassword\"}}`\n\n### Change the current user's email address\n* PUT request to /api/account\n* Body should be JSON encoded `{account: {email: \"new_email@example.com\"}}`\n* This will send an email containing the confirmation token.\n* The change will only be effective after the email address was confirmed.\n\n\n## TODO:\n* Better documentation\n* Clean up expired authentication tokens in the db\n* Merge the Joken secret_key config into the phoenix_token_auth config.\n* Custom work factor config for crypto_provider\n* Allow use of scrypt as an alternate crypto_provider\n* Example Ecto Phoenix migration, with indexes.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanukall%2Fphoenix_token_auth","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmanukall%2Fphoenix_token_auth","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmanukall%2Fphoenix_token_auth/lists"}