overriding rails authenticity_token setting

1.6k Views Asked by At

Submitting a form requires a token which the receiving server has named authenticity_token and is expecting a string that is known only to posting and receiving servers:

<input id="authenticity_token" name="authenticity_token" type="hidden" value="ac513de198a9f0536df5003fb5ba3122d1ee53d5" />

that value renders if I call an instance or global variable. However, even though the controller is set with the following filter:

  skip_before_action :verify_authenticity_token, only: [:reservation]

whether I try

<%= form_tag('https://test.webten.net/form') do %>
<%= hidden_field_tag :authenticity_token, @ppayment.authenticity_token, id: "authenticity_token" %>

or

<%= tag(:input, type: "hidden", name: request_forgery_protection_token.to_s, value: @ppayment.authenticity_token) %>

or

<input id="" name="authenticity_token" type="hidden" value="ac513de198a9f0536df5003fb5ba3122d1ee53d5" />

Rails ends up squashing each value with its own session setting value and rendering:

<input type="hidden" name="authenticity_token" id="authenticity_token" value="ydi5En1ywUkN5VsYIBXu6JTbQmXtwxNhpKlyjbbLi3RdvCc+A59EdDZvroGsGFplAAE5ATLcSqw25LVQkyPtKw==">
<input type="hidden" name="authenticity_token" value="ydi5En1ywUkN5VsYIBXu6JTbQmXtwxNhpKlyjbbLi3RdvCc+A59EdDZvroGsGFplAAE5ATLcSqw25LVQkyPtKw==">
<input id="authenticity_token" name="authenticity_token" type="hidden" value="ydi5En1ywUkN5VsYIBXu6JTbQmXtwxNhpKlyjbbLi3RdvCc+A59EdDZvroGsGFplAAE5ATLcSqw25LVQkyPtKw==">

How can rails default behaviour be overridden in this controller action?

2

There are 2 best solutions below

0
Jerome On BEST ANSWER

[this answer is complementary to the preceeding one. It solves the issue, but in an inelegant manner]

Various possible avenues of solution appear incomplete / off the mark

  • form_authenticity_tokenis a view helper that returns the current session's authenticity token. Too late to act upon that as the layout may already invoke it
  • most voted response has a per action method protect_from_forgery for ignoring it for internal purposes. Still is too late as session already has issued it
  • a skip before action is just like the previous solution, too late, session token is issued
  • The rails guide is incorrect in stating: authenticity_token: 'external_token'

Aaron Breckenridge's answer provide a clue: "you probably have some JS that overwrites the authenticity token ", supported by this posting. Thus one could search the content of app directory and still not find a JS handler... when jquery-ujs, for example, is gem installed. Based on observed behaviour, it must be getting fired up every time it encounters name='authenticity-token' and sets the value based on the META tag (logical. why have 2 different tokens on same page...) - doing its job properly!

Literally, that token must not be generated upstream. So modifying the layout's header section:

<% unless  request.path == "/controller/action" %>
  <%= csrf_meta_tags %>
<% end %>

is a working solution. This solution gets pollution-prone for multiple paths. Another requires multiple layout handling... thus, file under 'kludgey'. (willing to entertain better one!)

3
Aaron Breckenridge On

You have to override the :authenticity_token argument in the form_tag call to prevent Rails from adding the session's authenticity token by default:

<%= form_tag('https://test.webten.net/form', authenticity_token: 'ac513de198a9f0536df5003fb5ba3122d1ee53d5') do %>

or:

<%= form_tag('https://test.webten.net/form', authenticity_token: false) do %>
  <%= hidden_field_tag 'authenticity_token', 'ac513de198a9f0536df5003fb5ba3122d1ee53d5' %>

If that doesn't work, you probably have some JS that overwrites the authenticity token you provided from the one in the META tag. Search for 'csrf-token' in your JS.

See http://guides.rubyonrails.org/form_helpers.html#forms-to-external-resources for more information.