AuthenticityToken and Javascript
Wednesday, August 6th, 2008
The CSRF protection built into Rails 2 presented an issue when trying to make POST requests from anything other than a standard form. Rather than exclude numerous actions from protect_from_forgery, I made use of this snippet I noticed at http://madhatted.com (although slightly changed since ‘const’ isn’t support by IE):
<%= javascript_tag "var AUTH_TOKEN = #{form_authenticity_token.inspect};" if protect_against_forgery? -%>
While this is probably most useful for heavily Javascript/AJAX reliant applications, a simple use-case for this is creating a POST request from an anchor tag without using the messy ‘:method => :post’
In your RHTML:
<%= link_to 'Vote For This!', vote_for_article_path(@article), :class => 'method-post' -%>;
In your JS:
var anchorMethodPost = Behavior.create({ onclick: function() { var f = document.createElement('form'); f.style.display = 'none'; this.element.parentNode.appendChild(f); f.method = 'POST'; f.action = this.element.href; if(AUTH_TOKEN) { var s = document.createElement('input'); s.setAttribute('type', 'hidden'); s.setAttribute('name', 'authenticity_token'); s.setAttribute('value', AUTH_TOKEN); f.appendChild(s); } f.submit(); return false; } }); Event.addBehavior({ 'a.method-post' : anchorMethodPost });
Note: the above example uses Dan Webb’s lowpro.
The code is shifted from the inline onclick attribute to your Javascript file; but now it’s reusable and cached. Pretty simple, but a lot cleaner.
If one was being genuinely unobtrusive; however, it would probably be best to start off with a full form and submit tag, and then switch that to an anchor tag through Javascript… if POSTable anchor tags are really that necessary that is…