{"id":14966362,"url":"https://github.com/yiisoft/csrf","last_synced_at":"2025-04-28T15:51:03.490Z","repository":{"id":39906345,"uuid":"289267305","full_name":"yiisoft/csrf","owner":"yiisoft","description":"PSR-15 middleware implementing CSRF protection","archived":false,"fork":false,"pushed_at":"2025-03-05T13:54:53.000Z","size":157,"stargazers_count":26,"open_issues_count":4,"forks_count":7,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-04-19T18:26:13.522Z","etag":null,"topics":["csrf","hacktoberfest","middleware","psr-15","yii3"],"latest_commit_sha":null,"homepage":"https://www.yiiframework.com/","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yiisoft.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE.md","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"open_collective":"yiisoft","github":["yiisoft"]}},"created_at":"2020-08-21T12:43:39.000Z","updated_at":"2025-03-05T13:54:54.000Z","dependencies_parsed_at":"2023-12-13T03:35:14.979Z","dependency_job_id":"a694c423-0067-42cc-aab6-5d85a94cd366","html_url":"https://github.com/yiisoft/csrf","commit_stats":{"total_commits":90,"total_committers":17,"mean_commits":5.294117647058823,"dds":0.6777777777777778,"last_synced_commit":"b26cf68f91d244ea33b7d7358f9651c72d25371b"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":"yiisoft/package-template","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yiisoft%2Fcsrf","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yiisoft%2Fcsrf/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yiisoft%2Fcsrf/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yiisoft%2Fcsrf/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yiisoft","download_url":"https://codeload.github.com/yiisoft/csrf/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250541869,"owners_count":21447595,"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":["csrf","hacktoberfest","middleware","psr-15","yii3"],"created_at":"2024-09-24T13:36:16.418Z","updated_at":"2025-04-28T15:51:03.472Z","avatar_url":"https://github.com/yiisoft.png","language":"PHP","funding_links":["https://opencollective.com/yiisoft","https://github.com/sponsors/yiisoft"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://github.com/yiisoft\" target=\"_blank\"\u003e\n        \u003cimg src=\"https://yiisoft.github.io/docs/images/yii_logo.svg\" height=\"100px\" alt=\"Yii\"\u003e\n    \u003c/a\u003e\n    \u003ch1 align=\"center\"\u003eYii CSRF Protection Library\u003c/h1\u003e\n    \u003cbr\u003e\n\u003c/p\u003e\n\n[![Latest Stable Version](https://poser.pugx.org/yiisoft/csrf/v)](https://packagist.org/packages/yiisoft/csrf)\n[![Total Downloads](https://poser.pugx.org/yiisoft/csrf/downloads)](https://packagist.org/packages/yiisoft/csrf)\n[![Build status](https://github.com/yiisoft/csrf/actions/workflows/build.yml/badge.svg)](https://github.com/yiisoft/csrf/actions/workflows/build.yml)\n[![Code coverage](https://codecov.io/gh/yiisoft/csrf/graph/badge.svg?token=APV7NMIAB1)](https://codecov.io/gh/yiisoft/csrf)\n[![Mutation testing badge](https://img.shields.io/endpoint?style=flat\u0026url=https%3A%2F%2Fbadge-api.stryker-mutator.io%2Fgithub.com%2Fyiisoft%2Fcsrf%2Fmaster)](https://dashboard.stryker-mutator.io/reports/github.com/yiisoft/csrf/master)\n[![static analysis](https://github.com/yiisoft/csrf/workflows/static%20analysis/badge.svg)](https://github.com/yiisoft/csrf/actions?query=workflow%3A%22static+analysis%22)\n[![type-coverage](https://shepherd.dev/github/yiisoft/csrf/coverage.svg)](https://shepherd.dev/github/yiisoft/csrf)\n\nThe package provides [PSR-15](https://www.php-fig.org/psr/psr-15/) middleware for CSRF protection:\n\n- It supports two algorithms out of the box:\n  - Synchronizer CSRF token with customizable token generation and storage. By default, it uses random data and session.\n  - HMAC based token with customizable identity generation. Uses session by default.\n- It has ability to apply masking to CSRF token string to make [BREACH attack](https://breachattack.com/) impossible.\n- It supports CSRF protection by custom header for AJAX/SPA backend API.\n\n## Requirements\n\n- PHP 7.4 or higher.\n\n## Installation\n\nThe package could be installed with [Composer](https://getcomposer.org):\n\n```shell\ncomposer require yiisoft/csrf\n```\n\n## General usage\n\nIn order to enable CSRF protection you need to add `CsrfTokenMiddleware` to your main middleware stack.\nIn Yii it is done by configuring [`MiddlewareDispatcher`](https://github.com/yiisoft/middleware-dispatcher):\n\n```php\n$middlewareDispatcher = $injector-\u003emake(MiddlewareDispatcher::class);\n$middlewareDispatcher = $middlewareDispatcher-\u003ewithMiddlewares([\n    ErrorCatcher::class,\n    SessionMiddleware::class,\n    CsrfTokenMiddleware::class, // \u003c-- add this\n    Router::class,\n]);\n```\n\nor define the `MiddlewareDispatcher` configuration in the [DI container](https://github.com/yiisoft/di):\n\n```php\n// config/web/di/application.php\nreturn [\n    MiddlewareDispatcher::class =\u003e [\n        'withMiddlewares()' =\u003e [[\n            ErrorCatcher::class,\n            SessionMiddleware::class,\n            CsrfTokenMiddleware::class, // \u003c-- add this\n            Router::class,\n        ]]\n    ],\n];\n```\n\nBy default, CSRF token is obtained from `_csrf` request body parameter or `X-CSRF-Token` header.\n\nYou can access currently valid token as a string using `CsrfTokenInterface`:\n\n```php\n/** @var Yiisoft\\Csrf\\CsrfTokenInterface $csrfToken */\n$csrf = $csrfToken-\u003egetValue();\n```\n\nIf the token does not pass validation, the response `422 Unprocessable Entity` will be returned.\nYou can change this behavior by implementing your own request handler:\n\n```php\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse Psr\\Http\\Message\\ServerRequestInterface;\nuse Psr\\Http\\Server\\RequestHandlerInterface;\nuse Yiisoft\\Csrf\\CsrfTokenMiddleware;\n\n/**\n * @var Psr\\Http\\Message\\ResponseFactoryInterface $responseFactory\n * @var Yiisoft\\Csrf\\CsrfTokenInterface $csrfToken\n */\n \n$failureHandler = new class ($responseFactory) implements RequestHandlerInterface {\n    private ResponseFactoryInterface $responseFactory;\n    \n    public function __construct(ResponseFactoryInterface $responseFactory)\n    {\n        $this-\u003eresponseFactory = $responseFactory;\n    }\n\n    public function handle(ServerRequestInterface $request): ResponseInterface\n    {\n        $response = $this-\u003eresponseFactory-\u003ecreateResponse(400);\n        $response\n            -\u003egetBody()\n            -\u003ewrite('Bad request.');\n        return $response;\n    }\n};\n\n$middleware = new CsrfTokenMiddleware($responseFactory, $csrfToken, $failureHandler);\n```\n\nBy default, `CsrfTokenMiddleware` considers `GET`, `HEAD`, `OPTIONS` methods as safe operations and doesn't perform CSRF validation. You can change this behavior as follows:\n\n```php\nuse Yiisoft\\Csrf\\CsrfTokenMiddleware;\nuse Yiisoft\\Http\\Method;\n\n$csrfTokenMiddleware = $container-\u003eget(CsrfTokenMiddleware::class);\n\n// Returns a new instance with the specified list of safe methods.\n$csrfTokenMiddleware = $csrfTokenMiddleware-\u003ewithSafeMethods([Method::OPTIONS]);\n\n// Returns a new instance with the specified header name.\n$csrfTokenMiddleware = $csrfTokenMiddleware-\u003ewithHeaderName('X-CSRF-PROTECTION');\n```\n\nor define the `CsrfTokenMiddleware` configuration in the [DI container](https://github.com/yiisoft/di):\n\n```php\n// config/web/di/csrf-token.php\nuse Yiisoft\\Csrf\\CsrfTokenMiddleware;\nuse Yiisoft\\Http\\Method;\n\nreturn [\n    CsrfTokenMiddleware::class =\u003e [\n        'withSafeMethods()' =\u003e [[Method::OPTIONS]],\n        'withHeaderName()' =\u003e ['X-CSRF-PROTECTION'],\n    ],\n];\n```\n\n## CSRF Tokens\n\nIn case Yii framework is used along with config plugin, the package is [configured](./config/di-web.php)\nautomatically to use synchronizer token and masked decorator. You can change that depending on your needs.\n\n### Synchronizer CSRF token\n\nSynchronizer CSRF token is a stateful CSRF token that is a unique random string. It is saved in persistent storage\navailable only to the currently logged-in user. The same token is added to a form. When the form is submitted,\ntoken that came from the form is compared against the token stored.\n\n`SynchronizerCsrfToken` requires implementation of the following interfaces:\n\n- `CsrfTokenGeneratorInterface` for generating a new CSRF token;\n- `CsrfTokenStorageInterface` for persisting a token between requests.\n\nPackage provides `RandomCsrfTokenGenerator` that generates a random token and\n`SessionCsrfTokenStorage` that persists a token between requests in a user session.\n\nTo learn more about the synchronizer token pattern,\n[check OWASP CSRF cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#synchronizer-token-pattern).\n\n### HMAC based token\n\nHMAC based token is a stateless CSRF token that does not require any storage. The token is a hash from session ID and\na timestamp used to prevent replay attacks. The token is added to a form. When the form is submitted, we re-generate\nthe token from the current session ID and a timestamp from the original token. If two hashes match, we check that the\ntimestamp is less than the token lifetime.\n\n`HmacCsrfToken` requires implementation of `CsrfTokenIdentityGeneratorInterface` for generating an identity.\nThe package provides `SessionCsrfTokenIdentityGenerator` that is using session ID thus making the session a token scope.\n\nParameters set via the `HmacCsrfToken` constructor are:\n\n- `$secretKey` — shared secret key used to generate the hash;\n- `$algorithm` — hash algorithm for message authentication. `sha256`, `sha384` or `sha512` are recommended;\n- `$lifetime` — number of seconds that the token is valid for.\n\nTo learn more about HMAC based token pattern\n[check OWASP CSRF cheat sheet](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html#hmac-based-token-pattern).\n\n### Stub CSRF token\n\nThe `StubCsrfToken` simply stores and returns a token string. It does not perform any additional validation.\nThis implementation can be useful when mocking CSRF token behavior during unit testing or when providing\nplaceholder functionality in temporary solutions.\n\n### Masked CSRF token\n\n`MaskedCsrfToken` is a decorator for `CsrfTokenInterface` that applies masking to a token string.\nIt makes [BREACH attack](https://breachattack.com/) impossible, so it is safe to use token in HTML to be later passed to\nthe next request either as a hidden form field or via JavaScript async request.\n\nIt is recommended to always use this decorator.\n\n## CSRF protection for AJAX/SPA backend API\n\nIf you are using a cookie to authenticate your AJAX/SPA, then you do need CSRF protection for the backend API.\n\n### Employing custom request header\n\nIn this pattern, AJAX/SPA frontend appends a custom header to API requests that require CSRF protection. No token is needed for this approach. This defense relies on the CORS preflight mechanism which sends an `OPTIONS` request to verify CORS compliance with the destination server. All modern browsers, according to the same-origin policy security model, designate requests with custom headers as \"to be preflighted\". When the API requires a custom header, you know that the request must have been preflighted if it came from a browser.\n\nThe header can be any arbitrary key-value pair, as long as it does not conflict with existing headers. Empty value is also acceptable.\n\n```\nX-CSRF-HEADER=1\n```\n\nWhen handling the request, the API checks for the existence of this header. If the header does not exist, the backend rejects the request as potential forgery. Employing a custom header allows to reject [simple requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS#simple_requests) that browsers do not designate as \"to be preflighted\" and permit them to be sent to any origin.\n\nIn order to enable CSRF protection you need to add `CsrfHeaderMiddleware` to the [`MiddlewareDispatcher`](https://github.com/yiisoft/middleware-dispatcher) configuration:\n\n```php\n$middlewareDispatcher = $injector-\u003emake(MiddlewareDispatcher::class);\n$middlewareDispatcher = $middlewareDispatcher-\u003ewithMiddlewares([\n    ErrorCatcher::class,\n    CsrfHeaderMiddleware::class, // \u003c-- add this\n    Router::class,\n]);\n```\n\nor in the [DI container](https://github.com/yiisoft/di):\n\n```php\n// config/web/di/application.php\nreturn [\n    MiddlewareDispatcher::class =\u003e [\n        'withMiddlewares()' =\u003e [[\n            ErrorCatcher::class,\n            CsrfHeaderMiddleware::class, // \u003c-- add this\n            Router::class,\n        ]]\n    ],\n];\n```\n\nor add `CsrfHeaderMiddleware` to the routes that must be protected to the [router](https://github.com/yiisoft/router) configuration:\n\n```php\n// config/web/di/router.php\nreturn [\n    RouteCollectionInterface::class =\u003e static function (RouteCollectorInterface $collector) use ($config) {\n        $collector\n            -\u003emiddleware(CsrfHeaderMiddleware::class) // \u003c-- add this\n            -\u003eaddGroup(Group::create(null)-\u003eroutes($routes));\n\n        return new RouteCollection($collector);\n    },\n];\n```\n\nBy default, `CsrfHeaderMiddleware` considers only `GET`, `HEAD`, `POST` methods as unsafe operations. Requests with other HTTP methods trigger CORS preflight and do not require CSRF header validation. You can change this behavior as follows:\n\n```php\nuse Yiisoft\\Csrf\\CsrfHeaderMiddleware;\nuse Yiisoft\\Http\\Method;\n\n$csrfHeaderMiddleware = $container-\u003eget(CsrfHeaderMiddleware::class);\n\n// Returns a new instance with the specified list of unsafe methods.\n$csrfHeaderMiddleware = $csrfHeaderMiddleware-\u003ewithUnsafeMethods([Method::POST]);\n\n// Returns a new instance with the specified header name.\n$csrfHeaderMiddleware = $csrfHeaderMiddleware-\u003ewithHeaderName('X-CSRF-PROTECTION');\n```\n\nor define the `CsrfHeaderMiddleware` configuration in the [DI container](https://github.com/yiisoft/di):\n\n```php\n// config/web/di/csrf-header.php\nuse Yiisoft\\Csrf\\CsrfHeaderMiddleware;\nuse Yiisoft\\Http\\Method;\n\nreturn [\n    CsrfHeaderMiddleware::class =\u003e [\n        'withUnsafeMethods()' =\u003e [[Method::POST]],\n        'withHeaderName()' =\u003e ['X-CSRF-PROTECTION'],\n    ],\n];\n```\n\nThe use of a custom request header for CSRF protection is based on the CORS Protocol. Thus, you **must** configure the CORS module to allow or deny cross-origin access to the backend API.\n\n\u003e**Warning**  \n\u003e\n\u003e`CsrfHeaderMiddleware` can be used to prevent forgery of same-origin requests and requests from the list of specific origins only.\n\n\n### Protecting same-origin requests\n\nIn this scenario:\n\n- AJAX/SPA frontend and API backend have the same origin.\n- Cross-origin requests to the API server are denied.\n- Simple CORS requests must be restricted.\n\n#### Configure CORS module\n\n- Responses to a CORS preflight requests **must not** contain CORS headers.\n- Responses to an actual requests **must not** contain CORS headers.\n\n#### Configure middlewares stack\n\nAdd `CsrfHeaderMiddleware` to the [`MiddlewareDispatcher`](https://github.com/yiisoft/middleware-dispatcher) configuration:\n\n```php\n$middlewareDispatcher = $injector-\u003emake(MiddlewareDispatcher::class);\n$middlewareDispatcher = $middlewareDispatcher-\u003ewithMiddlewares([\n    ErrorCatcher::class,\n    CsrfHeaderMiddleware::class, // \u003c-- add this\n    Router::class,\n]);\n```\n\nor to the routes that must be protected to the [router](https://github.com/yiisoft/router) configuration:\n\n```php\n$collector = $container-\u003eget(RouteCollectorInterface::class);\n$collector-\u003eaddGroup(\n    Group::create('/api')\n        -\u003emiddleware(CsrfHeaderMiddleware::class) // \u003c-- add this\n        -\u003eroutes($routes)\n);\n```\n\n#### Configure frontend requests\n\nOn the frontend add to the `GET`, `HEAD`, `POST` requests a custom header defined in the `CsrfHeaderMiddleware` with an empty or random value.\n\n```js\nlet response = fetch('https://example.com/api/whoami', {\n  headers: {\n    \"X-CSRF-HEADER\": crypto.randomUUID()\n  }\n});\n```\n\n### Protecting requests from the list of specific origins\n\nIn this scenario:\n\n- AJAX/SPA frontend and API backend have different origins.\n- Allow cross origin requests to the API server from the list of specific origins only.\n- Simple CORS requests must be restricted.\n\n#### Configure CORS module\n\n- A successful responses to a CORS preflight requests **must** contain appropriate CORS headers.\n- Responses to an actual requests **must** contain appropriate CORS headers.\n- Value of the CORS header `Access-Control-Allow-Origin` **must** contain origin from the predefined list.\n\n```\n// assuming frontend origin is https://example.com and backend origin is https://api.example.com\nAccess-Control-Allow-Origin: https://example.com\n```\n\n#### Configure middlewares stack\n\nAdd `CsrfHeaderMiddleware` to the [`MiddlewareDispatcher`](https://github.com/yiisoft/middleware-dispatcher) configuration:\n\n```php\n$middlewareDispatcher = $injector-\u003emake(MiddlewareDispatcher::class);\n$middlewareDispatcher = $middlewareDispatcher-\u003ewithMiddlewares([\n    ErrorCatcher::class,\n    CsrfHeaderMiddleware::class, // \u003c-- add this\n    Router::class,\n]);\n```\n\nor to the routes that must be protected to the [router](https://github.com/yiisoft/router) configuration:\n\n```php\n$collector = $container-\u003eget(RouteCollectorInterface::class);\n$collector-\u003eaddGroup(\n    Group::create('/api')\n        -\u003emiddleware(CsrfHeaderMiddleware::class) // \u003c-- add this\n        -\u003eroutes($routes)\n);\n```\n\n#### Configure frontend requests\n\nOn the frontend add to the `GET`, `HEAD`, `POST` requests a custom header defined in the `CsrfHeaderMiddleware` with an empty or random value.\n\n```js\nlet response = fetch('https://api.example.com/whoami', {\n  headers: {\n    \"X-CSRF-HEADER\": crypto.randomUUID()\n  }\n});\n```\n\n### Protecting requests passed from any origin\n\nIn this scenario:\n\n- AJAX/SPA frontend and API backend have different origins.\n- Allow cross origin requests to the API server from any origin.\n- All requests are considered unsafe and **must** be protected against CSRF with CSRF-token.\n\n#### Configure CORS module\n\n- A successful responses to a CORS preflight requests **must** contain appropriate CORS headers.\n- Responses to an actual requests **must** contain appropriate CORS headers.\n- The CORS header `Access-Control-Allow-Origin` has the same value as `Origin` header in the request.\n\n```\n$frontendOrigin = $request-\u003egetOrigin();\n\nAccess-Control-Allow-Origin: $frontendOrigin\n```\n\n#### Configure middlewares stack\n\nBy default, `CsrfTokenMiddleware` considers `GET`, `HEAD`, `OPTIONS` methods as safe operations and doesn't perform CSRF validation.\nIn JavaScript-based apps, requests are made programmatically; therefore, to increase application protection, the only `OPTIONS` method can be considered safe and need not be appended with a CSRF token header.\n\nConfigure `CsrfTokenMiddleware` safe methods:\n\n```php\nuse Yiisoft\\Csrf\\CsrfTokenMiddleware;\nuse Yiisoft\\Http\\Method;\n\n$csrfTokenMiddleware = $container-\u003eget(CsrfTokenMiddleware::class);\n$csrfTokenMiddleware = $csrfTokenMiddleware-\u003ewithSafeMethods([Method::OPTIONS]);\n```\n\nor in the [DI container](https://github.com/yiisoft/di):\n\n```php\n// config/web/di/csrf-token.php\nuse Yiisoft\\Csrf\\CsrfTokenMiddleware;\nuse Yiisoft\\Http\\Method;\n\nreturn [\n    CsrfTokenMiddleware::class =\u003e [\n        'withSafeMethods()' =\u003e [[Method::OPTIONS]],\n    ],\n];\n```\n\nAdd `CsrfTokenMiddleware` to the [`MiddlewareDispatcher`](https://github.com/yiisoft/middleware-dispatcher) configuration:\n\n```php\n$middlewareDispatcher = $injector-\u003emake(MiddlewareDispatcher::class);\n$middlewareDispatcher = $middlewareDispatcher-\u003ewithMiddlewares([\n    ErrorCatcher::class,\n    SessionMiddleware::class,\n    CsrfTokenMiddleware::class, // \u003c-- add this\n    Router::class,\n]);\n```\n\nor to the routes that must be protected to the [router](https://github.com/yiisoft/router) configuration:\n\n```php\n$collector = $container-\u003eget(RouteCollectorInterface::class);\n$collector-\u003eaddGroup(\n    Group::create('/api')\n        -\u003emiddleware(CsrfTokenMiddleware::class) // \u003c-- add this\n        -\u003eroutes($routes)\n);\n```\n\n#### Configure routes\n\nCreate a route for acquiring CSRF-tokens from the frontend application to the [router](https://github.com/yiisoft/router) configuration.\n\n```php\nuse Psr\\Http\\Message\\ResponseFactoryInterface;\nuse Psr\\Http\\Message\\ResponseInterface;\nuse Yiisoft\\Http\\Header;\nuse Yiisoft\\Http\\Method;\nuse Yiisoft\\Router\\Route;\n\nRoute::options('/csrf-token')\n    -\u003eaction(static function (\n        ResponseFactoryInterface $responseFactory,\n        CsrfTokenInterface $token\n    ): ResponseInterface {\n        $tokenValue = $token-\u003egetValue();\n\n        $response = $responseFactory-\u003ecreateResponse()\n            -\u003ewithHeader(Header::ALLOW, Method::OPTIONS)\n            -\u003ewithHeader('X-CSRF-TOKEN', $tokenValue);\n\n        $response-\u003egetBody()-\u003ewrite($tokenValue);\n\n        return $response;\n    }),\n```\n\n#### Configure frontend requests\n\nOn the frontend first make a request to the configured endpoint and acquire a CSRF-token to use it in the subsequent requests.\n\n```js\nlet response = await fetch('https://api.example.com/csrf-token');\n\nlet csrfToken = await response.text();\n// OR\nlet csrfToken = response.headers.get('X-CSRF-TOKEN');\n```\n\nAdd to all requests a custom header defined in the `CsrfTokenMiddleware` with acquired CSRF-token value.\n\n```js\nlet response = fetch('https://api.example.com/whoami', {\n  headers: {\n    \"X-CSRF-TOKEN\": csrfToken\n  }\n});\n```\n\n## Documentation\n\n- [Internals](docs/internals.md)\n\nIf you need help or have a question, the [Yii Forum](https://forum.yiiframework.com/c/yii-3-0/63) is a good place for that.\nYou may also check out other [Yii Community Resources](https://www.yiiframework.com/community).\n\n## License\n\nThe Yii CSRF Protection Library is free software. It is released under the terms of the BSD License.\nPlease see [`LICENSE`](./LICENSE.md) for more information.\n\nMaintained by [Yii Software](https://www.yiiframework.com/).\n\n## Support the project\n\n[![Open Collective](https://img.shields.io/badge/Open%20Collective-sponsor-7eadf1?logo=open%20collective\u0026logoColor=7eadf1\u0026labelColor=555555)](https://opencollective.com/yiisoft)\n\n## Follow updates\n\n[![Official website](https://img.shields.io/badge/Powered_by-Yii_Framework-green.svg?style=flat)](https://www.yiiframework.com/)\n[![Twitter](https://img.shields.io/badge/twitter-follow-1DA1F2?logo=twitter\u0026logoColor=1DA1F2\u0026labelColor=555555?style=flat)](https://twitter.com/yiiframework)\n[![Telegram](https://img.shields.io/badge/telegram-join-1DA1F2?style=flat\u0026logo=telegram)](https://t.me/yii3en)\n[![Facebook](https://img.shields.io/badge/facebook-join-1DA1F2?style=flat\u0026logo=facebook\u0026logoColor=ffffff)](https://www.facebook.com/groups/yiitalk)\n[![Slack](https://img.shields.io/badge/slack-join-1DA1F2?style=flat\u0026logo=slack)](https://yiiframework.com/go/slack)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyiisoft%2Fcsrf","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyiisoft%2Fcsrf","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyiisoft%2Fcsrf/lists"}