Search by

wilycode / form-csrf

szymonpietrek-design

Optional session-backed CSRF token field and validator for WilyCode Form.

Package info

github.com/wilycode/form-csrf

pkg:composer/wilycode/form-csrf

Statistics

Installs: 9

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

v0.1.0 2026-10-27 13:17 UTC

This package is auto-updated.

Last update: 2026-10-27 13:19:57 UTC


README

PHP 8.4+ MIT License Tests

Optional session-backed CSRF protection for WilyCode Form. Provides a transparent form field, a standalone validator, and a framework-independent token manager.

WilyCode PHP Ecosystem

Part of WilyCode — independent PHP 8.4+ packages with separate repositories, releases and Composer installations.

Explore the WilyCode ecosystem

Requirements and installation

  • PHP 8.4 or newer.
  • wilycode/form v0.1.1 or newer (within the ^0.1 series), wilycode/session and wilycode/validator.
  • A SessionInterface implementation such as wilycode/session-php.

Once the new repository has been published and tagged, install:

composer require wilycode/form-csrf:^0.1 wilycode/session-php:^0.1

This package does not force a PHP native session dependency. Install wilycode/form v0.1.1 or newer first; v0.1.0 does not support transparent fields.

Quick start

use WilyCode\Form\Form;
use WilyCode\FormCsrf\CsrfTokenField;
use WilyCode\FormCsrf\SessionCsrfTokenManager;
use WilyCode\Session\Php\NativeSession;

$manager = new SessionCsrfTokenManager(new NativeSession());

final class ContactForm extends Form
{
    public function __construct(private readonly SessionCsrfTokenManager $manager)
    {
        parent::__construct();
    }

    protected function init(): void
    {
        $this->add(new CsrfTokenField($this->manager, 'contact'));
        $this->addField('name');
        $this->addField('email');
    }
}

// Render GET:
$form = new ContactForm($manager);
$token = $form->getField('_csrf')->getToken();
// <input type="hidden" name="_csrf" value="(HTML-escaped token)">

// Process POST: supply the request parsed body through setRequest($request).
$form = (new ContactForm($manager))->setRequest($request);
if ($form->isSubmittedAndValid()) {
    $data = $form->getData(); // Contains name, email; not _csrf.
    // Persist $data.
} elseif ($form->isSubmitted() && $form->getField('_csrf')->getErrors()->hasErrors()) {
    // Return HTTP 403 for an invalid or missing token.
}

Form::getDataByName('_csrf') returns the submitted token; CsrfTokenField::getToken() returns the current server-generated token. Never use submitted data to populate the hidden input.

The base wilycode/form library already registers custom fields with add(Field|Fieldset|Collection $element). No changes to addField() are needed.

Behavior

  • Cryptographically random 32-byte token encoded as a 64-character hex string.
  • Stable for a session and form ID; different forms and sessions get different values.
  • Constant-time comparison with hash_equals().
  • Validation never creates a token; missing stored tokens fail closed.
  • Submitted tokens are validated as ordinary form fields; a missing token fails the required-field check, while a non-empty invalid token fails CsrfTokenValidator (validation.csrf_token.invalid).
  • CSRF fields are transparent: validated normally but excluded from getData() and getDataWithExcludes(). getDataByName() continues to work.
  • Default field-level filters are not inherited, to avoid silently normalizing a security token. General form-wide filters can still alter the input array, so avoid modifying the _csrf key in those filters.
  • CSRF fields cannot be made optional (optional() throws), preventing accidental acceptance of a missing token.
  • Tokens are not one-time by default, so back navigation and multiple tabs remain usable. Regenerate the PHP session ID upon sign-in or privilege elevation; rotate the associated token namespace on authentication or privilege changes if you need to invalidate pre-login tokens (for example, $session->withNamespace('csrf')->clear()).

Security notes

CSRF tokens protect cookie-authenticated unsafe HTTP requests from cross-site submission. Use HTTPS in production, HttpOnly/Secure/SameSite session cookies as appropriate, and do not leak tokens to URLs, logs or third-party scripts. CSRF tokens do not replace authorization, input validation or XSS protection. Do not cache HTML containing session-specific tokens in a public shared cache.

API

Class Purpose
CsrfTokenField Required, transparent field with the CSRF validator and getToken() for rendering; cannot be optional
CsrfTokenValidator Validates a submitted scalar token using the configured manager
CsrfTokenManagerInterface Contract: getToken(formId), isValid(formId, token)
SessionCsrfTokenManager Stores tokens in a csrf namespace of SessionInterface

Development

composer install
composer validate --strict
composer test

License

MIT © 2026 Simon Piter. See LICENSE.