---
title: "Each form gets its own CSRF token in Rails 5"
description:
  "Rails 5 allows each form to have its own CSRF token to prevent hacking of the
  site."
canonical_url: "https://www.bigbinary.com/blog/per-form-csrf-token-in-rails-5"
markdown_url: "https://www.bigbinary.com/blog/per-form-csrf-token-in-rails-5.md"
---

# Each form gets its own CSRF token in Rails 5

Rails 5 allows each form to have its own CSRF token to prevent hacking of the
site.

- Author: Prajakta Tambe
- Published: January 11, 2016
- Categories: Rails 5, Rails

We have [written an extensive blog](csrf-and-rails) on what **CSRF** is and what
steps Rails 4 takes to prevent CSRF. We encourage you to read that blog to fully
understand rest of this article.

## Nested form can get around CSRF protection offered by Rails 4

A typical form generated in Rails 4 might look like this.

```plaintext

<form method= "post" action="/money_transfer">
  <input type="hidden" name="authenticity_token" value="token_value">
</form>

```

Using code-injection, a Hacker can add another form tag above the form tag
generated by Rails using JavaScript. Now the markup looks like this.

```plaintext

<form method="post" action="http://www.fraud.com/fraud">
  <form method= "post" action="/money_transfer">
    <input type="hidden" name="authenticity_token" value="token_value">
  </form>
</form>

```

HTML specification
[does not allow nested forms](http://stackoverflow.com/questions/379610/can-you-nest-html-forms).

Since nested forms are not allowed browser will accept the top most level form.
In this case that happens to be the form created by the hacker. When this form
is submitted then "authenticity_token" is also submitted and Rails will do its
check and will say everything is looking good and thus hacker will be able to
hack the site.

## Rails 5 fixes the issue by generating a custom token for a form

In Rails 5,
[CSRF token can be added for each form](https://github.com/rails/rails/pull/22275).
Each CSRF token will be valid only for the method/action of the form it was
included in.

You can add following line to your controller to add authenticity token specific
to method and action in each form tag of the controller.

```ruby

class UsersController < ApplicationController
  self.per_form_csrf_tokens = true
end

```

Adding that code to each controller feels burdensome. In that case you can
enable this behavior for all controllers in the application by adding following
line to an initializer.

```ruby

# config/application.rb
Rails.configuration.action_controller.per_form_csrf_tokens = true

```

This will add authenticity token specific to method and action in each form tag
of the application. After adding that token the generated form might look like
as shown below.

```plaintext

<form method= "post" action="/money_transfer">
  <input type="hidden" name="authenticity_token" value="money_transfer_post_action_token">
</form>

```

Authenticity token included here will be specific to action `money_transfer` and
method `post`. Attacker can still grab authenticity_token here, but attack will
be limited to `money_transfer post` action.

## Links

- [Human page](https://www.bigbinary.com/blog/per-form-csrf-token-in-rails-5)
