Final Class Yiisoft\Csrf\CsrfTokenCookieMiddleware
| Inheritance | Yiisoft\ |
|---|---|
| Implements | Psr\ |
PSR-15 middleware that publishes the current CSRF token in a JavaScript-readable response cookie.
It is intended for AJAX/SPA clients that read the token from a cookie and send it back explicitly in a request
header (the "cookie-to-header" pattern), for example Inertia and Axios which use the XSRF-TOKEN cookie and the
X-XSRF-TOKEN header.
The middleware only writes the cookie. Token validation stays the responsibility of {@see \
A Set-Cookie header does not by itself prevent a response from being cached (RFC 9111 section 7.3). A cached
response may replay a stale token, or reach a shared (proxy or CDN) cache and hand one user's token to another. By
default the middleware guards against this by setting Cache-Control: no-store on every response it touches; see
the $cacheControl constructor parameter to change or disable this.
Public Methods
| Method | Description | Defined By |
|---|---|---|
| __construct() | The cookie name, path and domain are checked only for control characters and ; to prevent response header
injection; making sure they are otherwise valid is up to the caller. |
Yiisoft\ |
| process() | Yiisoft\ |
Constants
| Constant | Value | Description | Defined By |
|---|---|---|---|
| COOKIE_NAME | 'XSRF-TOKEN' | Yiisoft\ |
|
| PATTERN_HEADER_INJECTION | '/[\ |
Control characters (including CR and LF) and the ; attribute separator. These would let a configured
cookie name, path or domain inject extra attributes or split the response header. Whether the values are
otherwise well-formed is left to the caller.
|
Yiisoft\ |
| SAME_SITE_LAX | 'Lax' | Yiisoft\ |
|
| SAME_SITE_NONE | 'None' | Yiisoft\ |
|
| SAME_SITE_STRICT | 'Strict' | Yiisoft\ |
Method Details
The cookie name, path and domain are checked only for control characters and ; to prevent response header
injection; making sure they are otherwise valid is up to the caller.
| public mixed __construct ( Yiisoft\ | ||
| $token | Yiisoft\ |
The CSRF token to publish. |
| $cookieName | string |
The name of the cookie holding the token. |
| $path | string |
The |
| $domain | string|null |
The |
| $secure | boolean|null |
Whether the cookie should only be sent over HTTPS. A non-null value is used as given.
When |
| $sameSite | string|null |
The |
| $cacheControl | boolean|string |
How to handle the |
| throws | InvalidArgumentException |
When a cookie attribute or the |
|---|---|---|
public function __construct(
CsrfTokenInterface $token,
string $cookieName = self::COOKIE_NAME,
string $path = '/',
?string $domain = null,
?bool $secure = null,
?string $sameSite = self::SAME_SITE_LAX,
$cacheControl = true
) {
if (preg_match(self::PATTERN_HEADER_INJECTION, $cookieName)) {
throw new InvalidArgumentException(
sprintf('The cookie name "%s" contains invalid characters.', $cookieName),
);
}
if (preg_match(self::PATTERN_HEADER_INJECTION, $path)) {
throw new InvalidArgumentException(
sprintf('The cookie path "%s" contains invalid characters.', $path),
);
}
if ($domain !== null && preg_match(self::PATTERN_HEADER_INJECTION, $domain)) {
throw new InvalidArgumentException(
sprintf('The cookie domain "%s" contains invalid characters.', $domain),
);
}
$allowedSameSite = [self::SAME_SITE_LAX, self::SAME_SITE_STRICT, self::SAME_SITE_NONE];
if ($sameSite !== null && !in_array($sameSite, $allowedSameSite, true)) {
throw new InvalidArgumentException(
sprintf('The "SameSite" attribute value "%s" is not valid.', $sameSite),
);
}
if ($sameSite === self::SAME_SITE_NONE && $secure === false) {
throw new InvalidArgumentException(
'The "secure" flag is required for cookies with "SameSite" attribute set to "None".',
);
}
/**
* The parameter has no native type because a `bool|string` union is not available on PHP 7.4, so a value of
* any other type can still be passed at runtime. Once the minimum PHP version is 8.0+, type the parameter as
* `bool|string` and remove this check together with the suppression below.
*
* @psalm-suppress DocblockTypeContradiction
*/
if (!is_bool($cacheControl) && !is_string($cacheControl)) {
throw new InvalidArgumentException(
sprintf('The "cacheControl" argument must be a bool or a string, "%s" given.', gettype($cacheControl)),
);
}
$this->token = $token;
$this->cookieName = $cookieName;
$this->path = $path;
$this->domain = $domain;
$this->secure = $secure;
$this->sameSite = $sameSite;
$this->cacheControl = $cacheControl;
}
| public \ | ||
| $request | \ |
|
| $handler | \ |
|
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$response = $handler->handle($request);
$response = $response->withAddedHeader(Header::SET_COOKIE, $this->buildCookieHeaderValue($request));
return $this->applyCacheControl($response);
}
User Contributed Notes
Leave a comment
Join the conversation to share a note.