{"id":13491546,"url":"https://github.com/railsmechanic/zachaeus","last_synced_at":"2025-05-07T19:20:38.269Z","repository":{"id":57558387,"uuid":"228231842","full_name":"railsmechanic/zachaeus","owner":"railsmechanic","description":"An easy to use licensing system, using asymmetric cryptography to generate and validate licenses.","archived":false,"fork":false,"pushed_at":"2020-01-13T08:39:08.000Z","size":99,"stargazers_count":19,"open_issues_count":0,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-18T09:46:58.707Z","etag":null,"topics":["api","authentication","easy-to-use","jwt","nacl","paseto"],"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/railsmechanic.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":"2019-12-15T18:34:28.000Z","updated_at":"2024-12-18T23:55:11.000Z","dependencies_parsed_at":"2022-08-28T11:41:38.493Z","dependency_job_id":null,"html_url":"https://github.com/railsmechanic/zachaeus","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/railsmechanic%2Fzachaeus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/railsmechanic%2Fzachaeus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/railsmechanic%2Fzachaeus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/railsmechanic%2Fzachaeus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/railsmechanic","download_url":"https://codeload.github.com/railsmechanic/zachaeus/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252941308,"owners_count":21828848,"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":["api","authentication","easy-to-use","jwt","nacl","paseto"],"created_at":"2024-07-31T19:00:58.084Z","updated_at":"2025-05-07T19:20:38.233Z","avatar_url":"https://github.com/railsmechanic.png","language":"Elixir","funding_links":[],"categories":["Elixir","Authentication"],"sub_categories":[],"readme":"# Zachaeus\nZachaeus is a simple and easy to use licensing system for your Elixir application.\nIt's inspired by JWT, PASETO and other security token systems, which are using asymmetric cryptography.\n\nA generated Zachaeus license contains all relevant data, which is essential for a simple licensing system.\nBecause of this nature, Zachaeus can be used without a database and integrates with Plug but can be used outside of it.\nIf you're implementing something which needs a licensing system, Zachaeus can work for you.\n\n## Use cases\n- Control access to web endpoints (Plug/Phoenix/\u003cyour framework\u003e)\n- Build software, where you want to issue licenses in order to control access and the functional scope\n- Restrict access to any kind of software\n\n## Features\n- Generate public/private key(s) with a mix task\n- Generate license(s) with a mix task and the given license data\n- Contains an authentication plug which is compatible with web frameworks e.g. Phoenix\n- No need to store the private key, used for license generation, on servers outside your organization\n- A license contains all relevant data, therefore you don't even need a database\n\n## Documentation\nAPI documentation is available at [https://hexdocs.pm/zachaeus](https://hexdocs.pm/zachaeus)\n\n## Installation\n#### Required libraries\nInstallation of Zachaeus requires the following libraries to be installed:\n- [libsodium](https://download.libsodium.org/doc/) - required for doing the hard work of signing/verifying\n\n#### Installation steps\nThe package can be installed as Hex package, just add Zachaeus to your application `mix.exs`\n\n```elixir\ndefp deps do\n  [{:zachaeus, \"~\u003e 1.0.0\"}]\nend\n```\n\nRun `mix deps.get` to fetch and install the package.\n\nTo leverage Zachaeus, you will need to generate a public/secret key pair by running the `mix zachaeus.gen.keys` task.\n\nAfter running this mix task, you need to add the generated key pair to your configuration `config/config.exs`.\n\n```elixir\nconfig :zachaeus,\n  public_key: \"csKWI0t9mdPoyEWfXj4skhZpjaMp...\",\n  secret_key: \"VkmBsZ5oklR8_MGk77AJUxDRpSqJL6449DTgK6y2f-hywpYjS32Z0...\"\n```\n\nAfter adding the key pair to your configuration file, you are able to generate license(s) using the `mix zachaeus.gen.license` task.\n\n```bash\n$ mix zachaeus.gen.license --identifier user_1 --plan default_plan --valid-from 2020-01-01 --valid-until 2020-12-31\n```\n\n🎉🎉 **Congratulations!** 🎉🎉\n\nYou now have a working Zachaeus setup.\n\n## Basics\nOnce Zachaeus was set up correctly, you can issue licenses using the `zachaeus.gen.license` mix task (as shown above) or with your own code. For issuing/signing licenses, Zachaeus requires either the configured secret key in your `config/config.exs` or a directly specified secret key.\n\n```elixir\n# Define a license with your specific license data\ndefined_license = %Zachaeus.License{\n  identifier: \"my_user_id_1\",\n  plan: \"default\",\n  valid_from: ~U[2018-11-15 11:00:00Z],\n  valid_until: ~U[2019-11-30 09:30:00Z]\n}\n\n# Sign the defined license using the configured secret key\nsigned_license = Zachaeus.sign(defined_license)\n\n# Verify the signed license using the configured public key\n{:ok, verified_license} = Zachaeus.verify(signed_license)\n\n# Verify the signed license with the configured public key and validate the license in a single step\n{:ok, 1123123} = Zachaeus.validate(signed_license)\n\n# Get a boolean indicator, whether the license could be verified with the configured public key and is valid\nZachaeus.valid?(signed_license) # -\u003e true\n```\n\n## Use with your web framework\nZachaeus comes with a default `EnsureAuthenticated` plug, which can be used with your plug compatible web framework e.g. Phoenix.\n\n```elixir\ndefmodule MyAppWeb.Router do\n  use Phoenix.Router\n\n  pipeline :api do\n    plug :accepts, [\"json\"]\n    plug Zachaeus.Plug.EnsureAuthenticated\n  end\n\n  scope \"/\" do\n    pipe_through :api\n    # API related routes...\n  end\nend\n```\n\nIf you need a custom behaviour, Zachaeus offers the ability to implement a fully customized plug on your own.\nJust `use Zachaeus.Plug` in your module and implement the default and the `build_response` callback.\n\n```elixir\ndefmodule CustomAuthentication do\n  use Zachaeus.Plug\n\n  def init(opts), do: opts\n\n  def call(conn, _opts) do\n    conn\n    |\u003e fetch_license()\n    |\u003e verify_license()\n    |\u003e validate_license()\n    |\u003e build_response()\n  end\n\n  def build_response({conn, {:ok, _license}}), do: conn\n  def build_response({conn, {:error, %Error{message: message}}}) do\n    conn\n    |\u003e put_resp_content_type(\"text/plain\")\n    |\u003e send_resp(:unauthorized, \"Dude, you don't have a valid license!\")\n    |\u003e halt()\n  end\nend\n```\n\n## Configuration\nTo keep Zachaeus configuration as simple as possible, it only needs a `secret_key` and/or a `public_key` (depending on your setup).\nAll configuration values may be provided in two ways.\n\n1. Through your config file(s)\n2. Passed directly to the function\n\nIf you don't want to store the configuration in the configuration file e.g. juggle with multiple keys or just to use keys stored within a database, all relevant functions like `sign/1`, `verify/1` etc. has a companion where the secret/public key can be specified directly.\n\n```elixir\n# Using the configured secret_key\nsigned_license = Zachaeus.sign(license)\n\n# Using a specific secret_key\ncustom_secret_key = \"thisisyourcustomsecretkey\"\nsigned_license    = Zachaeus.sign(license, custom_secrect_key)\n```\n\n### Configuration values\nThe Zachaeus configuration is really simple, as it just has the following configuration values:\n\n- `secret_key` - The key which is used to sign a license\n- `public_key` - The key which is used to verify a license\n\n_(The configuration values above are required for Zachaeus to work.)_\n\n### Key security / Split configuration\nDue to the nature of asymmetric cryptography, Zachaeus can be set up in a kind of _split configuration_.\nWith this type of configuration, you can keep your `secret_key` in a controlled and secure environment e.g. on your local computer and you just need to store the `public_key` outside of this secure environment e.g. on your web server.\n\nWhen you use this setup, you can generate licenses (using the `secret_key`) from within your secure environment, issue the licenses to your customers and verifying them (using the `public_key`) in an unsecure environment.\n\n#### License issuing system\nIt's just required to set the `secret_key` configuration value e.g. in your `config/config.exs`, but it wouldn't hurt either to set the `public_key` configuration value.\n\n```elixir\nconfig :zachaeus,\n  public_key: \"csKWI0t9mdPoyEWfXj4skhZpjaMp...\",\n  secret_key: \"VkmBsZ5oklR8_MGk77AJUxDRpSqJL6449DTgK6y2f-hywpYjS32Z0...\"\n```\n\n_\u0026#9658; Please keep in mind, that the verification of license only works, when the `public_key` configuration value is set!_\n\n#### License verifying system\nIt's strongly recommended to just set the `public_key` configuration value e.g. in your `config/config.exs` and not to set the `secret_key` configuration value.\n\n```elixir\nconfig :zachaeus,\n  public_key: \"csKWI0t9mdPoyEWfXj4skhZpjaMp...\"\n```\n\n_\u0026#9658; I recommend not to set the `secret_key` configuration value in a publicly available environment!_\n\n## Errors\nZachaeus offers the ability to customize the returned error message through general error codes.\n\n```elixir\n# Sample error\nsample_error = %Zachaeus.Error{code: :license_expired, message: \"The license has expired\"}\n\n# Match on the error code 'license_expired'\ncase sample_error do\n  %Zachaeus.Error{code: :license_expired} -\u003e\n    {:error, \"Hey dude, your license has expired!\"}\n  _any_other_error -\u003e\n    {:error, \"Something unexpected happened\"}\nend\n```\nHere's the current [list of errors](ERRORS.md) returned by Zachaeus.\n\n## License\nThe MIT License (MIT). Please see [License File](LICENSE) for more information.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frailsmechanic%2Fzachaeus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frailsmechanic%2Fzachaeus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frailsmechanic%2Fzachaeus/lists"}