{"id":18000122,"url":"https://github.com/rogersanctus/csrf_plus","last_synced_at":"2025-10-13T23:34:50.591Z","repository":{"id":195949549,"uuid":"694017546","full_name":"rogersanctus/csrf_plus","owner":"rogersanctus","description":"A plug-based CSRF protection library for Elixir","archived":false,"fork":false,"pushed_at":"2023-10-17T03:21:17.000Z","size":134,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-04T07:43:58.679Z","etag":null,"topics":["csrf","csrf-plus","csrf-protection","elixir","library","session","store"],"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/rogersanctus.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-09-20T07:03:30.000Z","updated_at":"2023-10-17T03:02:35.000Z","dependencies_parsed_at":"2023-09-20T09:01:30.445Z","dependency_job_id":"327d95b6-5a91-4afd-9139-2b2d57ad14a1","html_url":"https://github.com/rogersanctus/csrf_plus","commit_stats":null,"previous_names":["rogersanctus/csrf_plus"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/rogersanctus/csrf_plus","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogersanctus%2Fcsrf_plus","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogersanctus%2Fcsrf_plus/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogersanctus%2Fcsrf_plus/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogersanctus%2Fcsrf_plus/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rogersanctus","download_url":"https://codeload.github.com/rogersanctus/csrf_plus/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rogersanctus%2Fcsrf_plus/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279017235,"owners_count":26086015,"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-13T02:00:06.723Z","response_time":61,"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":["csrf","csrf-plus","csrf-protection","elixir","library","session","store"],"created_at":"2024-10-29T23:09:44.650Z","updated_at":"2025-10-13T23:34:50.573Z","avatar_url":"https://github.com/rogersanctus.png","language":"Elixir","funding_links":[],"categories":[],"sub_categories":[],"readme":"# CsrfPlus\nA plug-based CSRF (Cross-Site Request Forgery) protection library with accesses storing support.\n\nSometimes, you need more than a per-request CSRF tokens. This is why this Plug was created.\nThis plug supports storing tokens in any kind of storage system. And all you have to do is to\nimplement its `CsrfPlus.Store.Behaviour`. By doing so you will provide ways to put, get,\ndelete and other operations of accesses on that 'Store'.\n\n## How it works?\nWhen a request is made, this plug will check the request method type. Request methods intended\nfor reading data (GET, HEAD, OPTIONS) will be ignored, by default. The other requests will be\nchecked against the CSRF token stored in the connection session, in the `x-csrf-token` header\nand the one stored in the configured Store. All those tokens must match to each other to be\nconsidered valid. The first checkings are to ensure the tokens are given. Then, the token in\nthe session and the one in the Store are verified against each other. Later, the token on the\n`x-csrf-token` header that is a signed version of the generated token with the configured secret\nkey will be verified against that secret key. If this verification succeeds, the returned verified\ntoken will be checked against the token in the store. If this verification also succeeds, the\nconnection continues normally. Otherwise, if any of the checks fails, an exception will be raised\nand used to build the error message and response status code.\n\n## Usage\nYou can use CsrfPlus as a plug in your endpoint, router or in some plug pipeline. As this plug\nuses connection session, it must be plugged after `Plug.Session` and `Plug.Conn.fetch_session/2`.\nAlso, this plug won't check requests origin. So, to have safer connections, use some CORS lib of\nyour choice before CsrfPlus. A good choice is the [Corsica](https://github.com/whatyouhide/corsica) project.\n\nOne of the princeples of this plug is to avoid the most to do \"dark magic\". As so, you must generate the token and its signed version,\nprovide an `:access_id` and normal token in the user session and, store both the token and the `access_id` in the\nconfigured store and, finally, include the signed token in the `x-csrf-token` header. Usually, you do this step in\nresponse to a GET method request, thinking of a JSON API. But you can also use this plug with heex template\npages/components. More on the examples section.\n\nAnyway, we provide a helper function to get the tokens ready to be send in the response connection and stored\nin the configured store. This function is `CsrfPlus.put_token/2`. You will still need to generate, at least,\nthe token and its signed version. And to generate the token and its signed version you can use `CsrfPlus.Token.generate/0` that will\ngive you back a new token tuple at every call, or you can use the `CsrfPlus.get_token_tuple/1` that uses the `conn` struct to try to reuse\nthe token in the connection session or generate a new one when it's not possible. The use of the later function is prefferable when using\n_heex pages/components_.\n\nWhen using CORS, remmember to add the `x-csrf-token` header to the allowed and exposed headers. Also enable/allow the\nsession credentials.\n\n### The access\nTokens are stored as accesses and each access must have a unique id, the `access_id`. You can use `UUID.uuid4/0`\nto generate a unique id.\nThis `access_id` must be the same as the token in the session and the one in the store. This is because CsrfPlus\nwill, when checking a request, retrieve the `access_id` from the session and then use it to load the token in the\nstore. A found token with the given access id will be used later to test the tokens from session and `x-csrf-token`\nin the header.\n\n### Examples\n\nAn example project that uses phoenix heex pages can be found [here](https://github.com/rogersanctus/csrf_phx_example).\n\nAt the moment, LiveViews are not supported as they have a kind of hard coded validation through `Plug.CSRFProtection`. So if you want to\nuse LiveViews you must follow the instructions at `Phoenix.LiveView` [docs](https://hexdocs.pm/phoenix_live_view/welcome.html).\n\nFor an usage example on JSON Apis, check [recaptcha](https://github.com/rogersanctus/recaptcha) **(backend)** and\n[recaptcha-front](https://github.com/rogersanctus/recaptcha-front) **(frontend)**.\n\n## How to install?\nSimply, add `:csrf_plus` to you mix dependencies:\n\n```elixir\n# mix.exs\ndef deps do\n  [\n    {:plug, \"~\u003e 1.0\"},\n    {:csrf_plus, \"~\u003e 0.1\"}\n  ]\n```\n\nAnd then run `$ mix deps.get`.\n\n## Setting it up\n\n### Configs\n`CsrfPlus` uses some configurations to get ready to run.\n\n#### Token module\nThis module is responsible to generate and verify tokens.\nYou can create your own Token module, since you implement the `CsrfPlus.Token` behaviour.\n\nThis lib ships with a 'DefaultToken' module, that is used for that. But if you\nwant to set a custom Token module, use the config:\n\n```elixir\n# config/config.exs\nconfig :csrf_plus, CsrfPlus.Token, token_mod: YourTokenModule\n```\n\nWhen using the 'DefaultToken', you can define the function to be used to generate tokens\nor use the default one.\nTo config the token generator function add the following to your config:\n\n```elixir\n# config/config.exs\nconfig :csrf_plus, CsrfPlus.Token, token_generation_fn: \u0026your_function/0\n```\n\nSuch a function must return a string (binary) that is the token itself. That\ntoken must be unique.\n\nFinally, if you want to use the 'DefaultToken' module, you should set the\n`:secret_key` to be used to generate and verify tokens. That key must be at least 64\nbytes long.\n\nConfig with:\n\n```elixir\n# config/config.exs\nconfig :csrf_plus, CsrfPlus.Token, secret_key: \"a_good_strong_random_secret\"\n```\n\n\u003e #### Please note {: .info}\n\u003e This `:secret_key` is only needed if you are using the 'DefaultToken'\n\u003e module.\n\n#### Store module\nIn short, the store module is the module that implements the Store behaviour\nand will keep your generated tokens ready to be checked against. If any served\ntoken is not on the store, it is considered as invalid. For more information about\nStores look at the `CsrfPlu.Store.Behaviour` module.\nTo config the used store module, add the following:\n\n```elixir\n# config/config.exs\nconfig :csrf_plus, CsrfPlus, store: YourStoreModule\n```\n\nThere is no store set by default. But if you don't care about that, you can use\nthe builtin `CsrfPlus.Store.MemoryDb` store. As it names suggests, it will store\ntokens (accesses, actually) in memory, using a `GenServer`.\n\nIf so, do:\n\n```elixir\n# config/config.exs\nconfig :csrf_plus, CsrfPlus, store: CsrfPlus.Store.MemoryDb \n```\n\n### Options\nThe `CsrfPlus` plug accepts some options at its initialization.\nThe following options are available:\n\n  * `:csrf_key` - The key under the token is stored in the connection session. Defaults to: `\"_csrf_key_\"`\n\n  * `:allowed_methods` - The requests methods that are ignored by the CSRF token validations.\nBy defaut: `[\"GET\", \"HEAD\", \"OPTIONS\"]`.\n\n  * `:raise_exception?` - If true, exceptions thrown by `CsrfPlus` will not be caught, but reraised. Set this to false\n  to use the `ErrorMapper` and have response error and status code set. Defaults to `false`.\n\n  * `:error_mapper` - The module to be used to map exceptions to response status codes and error messages. The connection is halted\n  after the error is set.\n\n    There is a default module for that: `CsrfPlus.ErrorMapper`. But you can set your own module\n    since it implements the `CsrfPlus.ErrorMapper` behaviour. The `ErrorMapper` `map` function will only be used when\n    the option `:raise_exception?` is set to false.\n\n### Supervisor\nAs the CSRF validation of this lib uses a store of tokens, it's a good practice to\nlet them have a life span. And to keep the Store of tokens updated by this rule, we\nuse a store manager `CsrfPlus.Store.Manager` that will check all the tokens in the store\nand flag the expired tokens as so. That Manager can be started directly, but to make it\neasier to use with the default `CsrfPlus.Store.MemoryDb` store, we provide a `CsrfPlus.Supervisor` that\nwill not only start them, but also keep them up.\n\nTo start the Supervisor include the following entry in your application start function:\n\n```elixir\n# application.ex\ndef start(_type, _args) do\n  #...\n\n  children = [\n    #...\n    {CsrfPlus.Supervisor, opts}\n    #...\n  ]\n\n  #...\nend\n```\n\nReplace opts by the options you want to set for the `CsrfPlus.Store.Manager`.\nFor more information about the options look at the module documentation.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frogersanctus%2Fcsrf_plus","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frogersanctus%2Fcsrf_plus","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frogersanctus%2Fcsrf_plus/lists"}