CSRF protection for Ray.Di / BEAR.Resource applications.
ray/csrf keeps CSRF outside the Resource semantic contract: Resource method
parameters do not need a CSRF token, and request schemas / API documentation do
not need to expose it. Browser-facing unsafe methods are protected by Ray AOP
interceptors.
composer require ray/csrfInstall CsrfModule in your application module:
use Ray\Csrf\CsrfModule;
$this->install(new CsrfModule(
allowedOrigin: 'https://example.com',
tokenField: '_csrf_token',
));tokenField defaults to _csrf_token. Applications with an existing wire name
can override it, for example BeMart uses csrfToken:
$this->install(new CsrfModule(tokenField: 'csrfToken'));use Ray\Csrf\Attribute\CsrfToken;
use Ray\Csrf\Attribute\SameOrigin;
final class Article extends ResourceObject
{
#[SameOrigin]
#[CsrfToken]
public function onPost(string $title, string $body): static
{
// No csrfToken parameter: CSRF is a transport concern, not a
// Resource semantic argument.
return $this;
}
}#[SameOrigin] validates browser origin signals (Sec-Fetch-Site, Origin,
Referer). If allowedOrigin is null, only this origin gate is skipped.
#[CsrfToken] validates a synchroniser token and is not disabled by
allowedOrigin: null. Tests and fake contexts should override
CsrfTokenInterface when they do not drive real HTTP form submissions.
The submitted token is read in this order:
X-CSRF-TokenheaderResourceObject->uri->query[$field]$_POST[$field]
This keeps the token out of Resource method arguments while still supporting BEAR.Resource requests, HTML forms, and JavaScript submissions.
Issue a token through CsrfTokenInterface in your renderer or template helper
and render it as a hidden field:
<input type="hidden" name="_csrf_token" value="<?= $csrfToken ?>">The Resource does not need to know that this field exists.