---
title: "Rails 5 changes protect_from_forgery execution order"
description:
  "The default order of protect_from_forgery is changed from prepend to call
  order."
canonical_url: "https://www.bigbinary.com/blog/rails-5-default-protect-from-forgery-prepend-false"
markdown_url: "https://www.bigbinary.com/blog/rails-5-default-protect-from-forgery-prepend-false.md"
---

# Rails 5 changes protect_from_forgery execution order

The default order of protect_from_forgery is changed from prepend to call order.

- Author: Vijay Kumar Agrawal
- Published: April 6, 2016
- Categories: Rails 5, Rails

What makes Rails a great framework to work with is its sane
[conventions over configuration](http://rubyonrails.org/doctrine/#convention-over-configuration).
Rails community is always striving to keep these conventions relevant over time.
In this blog, we will see why and what changed in execution order of
`protect_from_forgery`.

`protect_from_forgery` protects applications against [CSRF](csrf-and-rails).
Follow that link to read up more about `CSRF`.

### What

If we generate a brand new Rails application in Rails 4.x then
`application_controller` will look like this.

```ruby
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
end
```

Looking it at the code it does not look like `protect_from_forgery` is a
`before_action` call but in reality that's what it is. Since
`protect_from_forgery` is a `before_action` call it should follow the order of
how other `before_action` are executed. But this one is special in the sense
that `protect_from_forgery` is executed first in the series of `before_action`
no matter where `protect_from_forgery` is mentioned. Let's see an example.

```ruby
class ApplicationController < ActionController::Base
  before_action :load_user
  protect_from_forgery with: :exception
end
```

In the above case even though `protect_from_forgery` call is made after
`load_user`, the protection execution happens first. And we can't do anything
about it. We can't pass any option to stop Rails from doing this.

Rails 5
[changes](https://github.com/rails/rails/commit/39794037817703575c35a75f1961b01b83791191)
this behavior by introducing a `boolean` option called `prepend`. Default value
of this option is `false`. What it means is, now `protect_from_forgery` gets
executed in order of call. Of course, this can be overridden by passing
`prepend: true` as shown below and now protection call will happen first just
like Rails 4.x.

```ruby
class ApplicationController < ActionController::Base
  before_action :load_user
  protect_from_forgery with: :exception, prepend: true
end
```

## Why

There isn't any real advantage in forcing `protect_from_forgery` to be the first
filter in the chain of filters to be executed. On the flip side, there are cases
where output of other `before_action` should decide the execution of
`protect_from_forgery`. Let's see an example.

```ruby

class ApplicationController < ActionController::Base
  before_action :authenticate
  protect_from_forgery unless: -> { @authenticated_by.oauth? }

  private
    def authenticate
      if oauth_request?
        # authenticate with oauth
        @authenticated_by = 'oauth'.inquiry
      else
        # authenticate with cookies
        @authenticated_by = 'cookie'.inquiry
      end
    end
end

```

Above code would fail in Rails 4.x, as `protect_from_forgery`, though called
after `:authenticate`, actually gets executed before it. Due to which we would
not have `@authenticated_by` set properly.

Whereas in Rails 5, `protect_from_forgery` gets executed after `:authenticate`
and gets skipped if authentication is oauth.

## Upgrading to Rails 5

Let's take an example to understand how this change might affect the upgrade of
applications from Rails 4 to Rails 5.

```ruby

class ApplicationController < ActionController::Base
  before_action :set_access_time
  protect_from_forgery

  private
    def set_access_time
      current_user.access_time = Time.now
      current_user.save
    end
end

```

In Rails 4.x, `set_access_time` is **not** executed for _bad requests_. But it
gets executed in Rails 5 because `protect_from_forgery` is called after
`set_access_time`.

Saving data (`current_user.save`) in `before_action` is anyways a big enough
violation of the best practices, but now those persistences would leave us
vulnerable to CSRF if they are called before `protect_from_forgery` is called.

## Links

- [Human page](https://www.bigbinary.com/blog/rails-5-default-protect-from-forgery-prepend-false)
