{"id":13561974,"url":"https://github.com/ueberauth/guardian_db","last_synced_at":"2025-04-03T17:32:10.316Z","repository":{"id":45063502,"uuid":"41658942","full_name":"ueberauth/guardian_db","owner":"ueberauth","description":"Guardian DB integration for tracking tokens and ensuring logout cannot be replayed.","archived":false,"fork":false,"pushed_at":"2023-11-13T19:09:40.000Z","size":213,"stargazers_count":369,"open_issues_count":2,"forks_count":87,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-03-09T08:02:45.953Z","etag":null,"topics":["database","guardian","guardian-db"],"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/ueberauth.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-08-31T06:12:04.000Z","updated_at":"2024-12-14T07:59:30.000Z","dependencies_parsed_at":"2024-05-01T15:27:42.202Z","dependency_job_id":"809b7f2b-0a04-484a-8779-2baaf01336d9","html_url":"https://github.com/ueberauth/guardian_db","commit_stats":{"total_commits":147,"total_committers":53,"mean_commits":"2.7735849056603774","dds":0.782312925170068,"last_synced_commit":"8cbe3a6cd42ee79afcb65383b2cc20d2afe87d7f"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ueberauth%2Fguardian_db","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ueberauth%2Fguardian_db/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ueberauth%2Fguardian_db/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ueberauth%2Fguardian_db/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ueberauth","download_url":"https://codeload.github.com/ueberauth/guardian_db/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247047155,"owners_count":20874785,"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":["database","guardian","guardian-db"],"created_at":"2024-08-01T13:01:03.190Z","updated_at":"2025-04-03T17:32:05.299Z","avatar_url":"https://github.com/ueberauth.png","language":"Elixir","funding_links":[],"categories":["Authentication"],"sub_categories":[],"readme":"# Guardian.DB\n\n[![Hex.pm](https://img.shields.io/hexpm/v/guardian_db.svg)](https://hex.pm/packages/guardian_db)\n![Build Status](https://github.com/ueberauth/guardian_db/workflows/Continuous%20Integration/badge.svg)\n[![Codecov](https://codecov.io/gh/ueberauth/guardian_db/branch/master/graph/badge.svg)](https://codecov.io/gh/ueberauth/guardian_db)\n[![Inline docs](https://inch-ci.org/github/ueberauth/guardian_db.svg)](https://inch-ci.org/github/ueberauth/guardian_db)\n\n`Guardian.DB` is an extension to `Guardian` that tracks tokens in your\napplication's database to prevent playback.\n\n## Installation\n\n`Guardian.DB` assumes that you are using the Guardian framework for\nauthentication.\n\nTo install `Guardian.DB`, first add it to your `mix.exs` file:\n\n```elixir\ndefp deps do\n  [\n    {:guardian_db, \"~\u003e 2.0\"}\n  ]\nend\n```\n\nThen run `mix deps.get` on your terminal.\n\nConfigure your application as seen in the *Configuration* section below prior to attempting to generate the migration or you will get an `application was not loaded/started` error.\n\nFollowing configuration add the Guardian migration:\n\nrun `mix guardian.db.gen.migration` to generate a migration.\n\n**Do not run the migration yet,** we need to complete our setup first.\n\n## Configuration\n\n```elixir\nconfig :guardian, Guardian.DB,\n  repo: MyApp.Repo, # Add your repository module\n  schema_name: \"guardian_tokens\", # default\n  token_types: [\"refresh_token\"], # store all token types if not set\n```\n\nTo sweep expired tokens from your db you should add\n`Guardian.DB.Sweeper` to your supervision tree.\n\n```elixir\nchildren = [\n  {Guardian.DB.Sweeper, [interval: 60 * 60 * 1000]} # 1 hour\n]\n```\n\n`Guardian.DB` works by hooking into the lifecycle of your `Guardian` module.\n\nYou'll need to add it to:\n\n* `after_encode_and_sign`\n* `on_verify`\n* `on_refresh`\n* `on_revoke`\n\nFor example:\n\n```elixir\ndefmodule MyApp.AuthTokens do\n  use Guardian, otp_app: :my_app\n\n  # snip...\n\n  def after_encode_and_sign(resource, claims, token, _options) do\n    with {:ok, _} \u003c- Guardian.DB.after_encode_and_sign(resource, claims[\"typ\"], claims, token) do\n      {:ok, token}\n    end\n  end\n\n  def on_verify(claims, token, _options) do\n    with {:ok, _} \u003c- Guardian.DB.on_verify(claims, token) do\n      {:ok, claims}\n    end\n  end\n\n  def on_refresh({old_token, old_claims}, {new_token, new_claims}, _options) do\n    with {:ok, _, _} \u003c- Guardian.DB.on_refresh({old_token, old_claims}, {new_token, new_claims}) do\n      {:ok, {old_token, old_claims}, {new_token, new_claims}}\n    end\n  end\n\n  def on_revoke(claims, token, _options) do\n    with {:ok, _} \u003c- Guardian.DB.on_revoke(claims, token) do\n      {:ok, claims}\n    end\n  end\nend\n```\n\nNow run the migration and you'll be good to go.\n\n### Custom schema name\n\n`Guardian.DB` allows custom schema name in migrations, based on following\nconfiguration:\n\n```elixir\nconfig :guardian, Guardian.DB,\n  schema_name: \"my_custom_schema\"\n```\n\nAnd when you run the migration, it'll generate the following migration:\n\n```elixir\n  create table(:my_custom_schema, primary_key: false) do\n    add(:jti, :string, primary_key: true)\n    add(:typ, :string)\n    add(:aud, :string)\n    add(:iss, :string)\n    add(:sub, :string)\n    add(:exp, :bigint)\n    add(:jwt, :text)\n    add(:claims, :map)\n    timestamps()\n  end\n```\n\nThen, run the migration and you'll be good to go.\n\n### Considerations\n\n`Guardian` is already a very robust JWT solution. However, if your\napplication needs the ability to immediately revoke and invalidate tokens that\nhave already been generated, you need something like `Guardian.DB` to build upon\n`Guardian`.\n\nIn `Guardian`, you as a systems administrator have no way of revoking\ntokens that have already been generated, you can call `Guardian.revoke`, but in\n`Guardian` **that function does not actually do anything** - it just provides\nhooks for other libraries, such as this one, to define more specific behavior.\nDiscarding the token after something like a log out action is left up to the\nclient application. If the client application does not discard the token, or\ndoes not log out, or the token gets stolen by a malicious script (because the\nclient application stores it in localStorage, for instance), the only thing you\ncan do is wait until the token expires. Depending on the scenario, this may not\nbe acceptable.\n\nWith `Guardian.DB`, records of all generated tokens are kept in your\napplication's database. During each request, the `Guardian.Plug.VerifyHeader`\nand `Guardian.Plug.VerifySession` plugs check the database to make sure the\ntoken is there. If it is not, the server returns a 401 Unauthorized response to\nthe client. Furthermore, `Guardian.revoke!` behavior becomes enhanced, as it\nactually removes the token from the database. This means that if the user logs\nout, or you revoke their token (e.g. after noticing suspicious activity on the\naccount), they will need to re-authenticate.\n\n### Disadvantages\n\nIn `Guardian`, token verification is very light-weight. The only thing\n`Guardian` does is decode incoming tokens and make sure they are valid. This can\nmake it much easier to horizontally scale your application, since there is no\nneed to centrally store sessions and make them available to load balancers or\nother servers.\n\nWith `Guardian.DB`, every request requires a trip to the database, as `Guardian`\nnow needs to ensure that a record of the token exists. In large scale\napplications this can be fairly costly, and can arguably eliminate the main\nadvantage of using a JWT authentication solution, which is statelessness.\nFurthermore, session authentication already works this way, and in most cases\nthere isn't a good enough reason to reinvent that wheel using JWTs.\n\nIn other words, once you have reached a point where you think you need\n`Guardian.DB`, it may be time to take a step back and reconsider your whole\napproach to authentication!\n\n### Create your own Repo\n\nWe created `Guardian.DB.Adapter` behaviour to allow creating other repositories for persisting JWT tokens.\nYou need to implement the `Guardian.DB.Adapter` behavior working with your preferred storage.\n\n### Adapters\n\n1. Redis adapter - [`guardian_redis`](https://github.com/alexfilatov/guardian_redis)\n\nFeel free to create your adapters using `Guardian.DB.Adapter` behavior and you are welcome to add them here.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fueberauth%2Fguardian_db","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fueberauth%2Fguardian_db","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fueberauth%2Fguardian_db/lists"}