NAME

Mojolicious::Plugin::CSRFProtectBuiltin - CSRF protection plugin using Mojolicious built-in CSRF support

SYNOPSIS

# Mojolicious
$self->plugin('TagHelpers');
$self->plugin('CSRFProtectBuiltin');

# Mojolicious::Lite
plugin 'TagHelpers';
plugin 'CSRFProtectBuiltin';

# Existing block-style form_for forms automatically receive a CSRF field
%= form_for '/login' => (method => 'POST') => begin
  %= text_field 'Username'
  %= password_field 'Password'
  %= submit_button 'Sign in'
% end

# Optional jQuery AJAX support
<%= jquery_ajax_csrf_protection %>

# Custom error handling
$self->plugin('CSRFProtectBuiltin' => {
  on_error => sub {
    my $c = shift;
    $c->render(template => 'error_403', status => 403);
  }
});

DESCRIPTION

Mojolicious::Plugin::CSRFProtectBuiltin adds CSRF protection to applications that already make heavy use of form_for, while relying on Mojolicious built-in CSRF helpers and validation.

It does the following:

  1. Wraps the form_for helper so block-style forms automatically get a csrf_field inserted at the start of the form body.

  2. Provides a jquery_ajax_csrf_protection helper that emits a meta tag with the current CSRF token and JavaScript to attach that token as an X-CSRF-Token header on jQuery AJAX requests.

  3. Rejects non GET, HEAD, and OPTIONS requests when csrf_protect validation fails.

This plugin uses Mojolicious built-in csrf_token, csrf_field, and csrf_protect support rather than implementing its own token generation and comparison logic.

CONFIGURATION

on_error

Optional callback used when CSRF validation fails.

If omitted, the plugin returns a simple 403 Forbidden! response.

Example:

$self->plugin('CSRFProtectBuiltin' => {
  on_error => sub {
    my $c = shift;
    $c->render(template => 'error_403', status => 403);
  }
});

HELPERS

form_for

This plugin replaces the existing form_for helper and prepends csrf_field to block-style forms.

So this:

%= form_for '/save' => (method => 'POST') => begin
  %= text_field 'name'
  %= submit_button 'Save'
% end

behaves as if you had written:

%= form_for '/save' => (method => 'POST') => begin
  %= csrf_field
  %= text_field 'name'
  %= submit_button 'Save'
% end

csrftoken

Returns the current Mojolicious CSRF token.

In templates:

<%= csrftoken %>

In controllers:

my $token = $self->csrftoken;

This is a compatibility helper for older code that expects a helper called csrftoken.

is_valid_csrftoken

Checks whether the current request contains a valid CSRF token.

Returns 1 for valid and 0 for invalid.

Example:

return $c->render(status => 403, text => 'Forbidden')
  unless $c->is_valid_csrftoken;

This is primarily a compatibility helper for code that previously used the older plugin API.

jquery_ajax_csrf_protection

Emits a meta tag containing the current CSRF token and a jQuery ajaxSend handler that adds the token as an X-CSRF-Token header to AJAX requests.

Add it in the page head or layout:

<%= jquery_ajax_csrf_protection %>

This helper is intended for jQuery-based AJAX only. If your application uses fetch, Axios, or raw XMLHttpRequest, you will need an equivalent custom JavaScript snippet.

HOW VALIDATION WORKS

For non GET, HEAD, and OPTIONS requests, the plugin calls:

$c->validation->csrf_protect

If validation fails, Mojolicious records an error on csrf_token, and the plugin invokes the configured on_error callback.

GET REQUESTS

This plugin does not automatically protect ordinary GET requests.

That is intentional, because navigation links and menu entries are normally GET, while CSRF protection is generally intended for state-changing requests such as POST, PUT, PATCH, and DELETE.

If you have a state-changing GET route, you should strongly consider changing it to POST. If that is not possible, protect it manually.

LIMITATIONS

SEE ALSO

Mojolicious, Mojolicious::Plugin::TagHelpers, Mojolicious::Plugin::DefaultHelpers, Mojolicious::Validator::Validation, Mojolicious::Plugin::CSRFProtect, Mojolicious::Plugin::CSRFDefender

AUTHOR

Adapted for Mojolicious built-in CSRF support.

LICENSE

Same terms as Perl itself.