respond_to and ActionController::InvalidAuthenticityToken

I have a create action that accepts both standard form POSTs and
Ajax-powered posts.

Traditionally I've forked the response to these requests by saying:

if request.xhr?
  # Do the new thing
else
  # Do the old thing
end

Tonight I switched to using respond_to.

Now I'm looking at two scenarios. One in which both standard form POSTs
AND Ajax posts are responded to with vanilla HTML. The other scenario is
created by adding contentType: 'text/javascript' to my Ajax request.
This results in the wonderful ActionController::InvalidAuthenticityToken
exception being raised.

So basically, if I don't specify text/javascript as the content-type of
the Ajax request, my format.js gets ignored. If I DO specify it, it
dies.

It worked before when I forked manually via if request.xhr?.

I also found that if I removed the respond.html it works fine (also
without specifying contentType: 'text/javascript' in my Ajax request).
This won't work because that action can be accessed traditionally and
via Ajax.

I'm not sure whether this is a cookie-related issue as the error would
lead me to believe, or if my Ajax request is somehow incorrect, thus
being ignored by respond_to.

Any ideas?

Daniel Waite wrote:

I have a create action that accepts both standard form POSTs and
Ajax-powered posts.

Traditionally I've forked the response to these requests by saying:

if request.xhr?
  # Do the new thing
else
  # Do the old thing
end

Tonight I switched to using respond_to.

Now I'm looking at two scenarios. One in which both standard form POSTs
AND Ajax posts are responded to with vanilla HTML. The other scenario is
created by adding contentType: 'text/javascript' to my Ajax request.
This results in the wonderful ActionController::InvalidAuthenticityToken
exception being raised.

So basically, if I don't specify text/javascript as the content-type of
the Ajax request, my format.js gets ignored. If I DO specify it, it
dies.

It worked before when I forked manually via if request.xhr?.

I also found that if I removed the respond.html it works fine (also
without specifying contentType: 'text/javascript' in my Ajax request).
This won't work because that action can be accessed traditionally and
via Ajax.

I'm not sure whether this is a cookie-related issue as the error would
lead me to believe, or if my Ajax request is somehow incorrect, thus
being ignored by respond_to.

Any ideas?

Apparently setting the contentType was the wrong thing to do. I'm not
changing the type of content I'm sending -- it's still a basic hash via
HTML forms. What I am changing is the header type. So I added this:

beforeSend: function(xhr) {xhr.setRequestHeader("Accept", "text/html");}

To to the definition of my Ajax request. Sweet.

Daniel Waite wrote:

beforeSend: function(xhr) {xhr.setRequestHeader("Accept", "text/html");}

Oops, I meant:
beforeSend: function(xhr) {xhr.setRequestHeader("Accept",
"text/javascript");},

If I had to take a stab at explaining what the problem was, I'd say that
by changing the contentType, Rails didn't "understand" the request, and
therefore couldn't "see" the authenticity token being passed in, thus
the exception.

I'll expand and say that jQuery let me down by not automatically setting
the request header to text/javascript.

Oh well, so long as it works.

I am having a similar problem.

I am on Rails 2.02 and when I execute the following REST call through
curl:

curl -H "Accept: application/json" -i -X GET http://localhost:3000/projects/3

Then that's fine and I get the description of the project with the
given ID.

But if I do the following through curl:

curl -X DELETE http://localhost:3000/projects/1

I do get an error message that

ActionController::InvalidAuthenticityToken

exception caught

what might be wrong about it?

Regards,

Exactly what it says: the authenticity token is invalid, in your case it
is simply absent. This token is part of the new request forgery
protection. If it is enabled with protect_from_forgery (see the API
docs) then for all actions, except those using the HTTP GET method, a
token must be send as a query parameter. Inside your app, you can get
at the token with form_authenticity_token; I have no good idea what to
do to access the app from the commandline with curl or similar.

In general, you have to request something from the app that includes the
authenticity token. It is automatically included in forms and in
destroy links.

Michael

Hi,

> I am having a similar problem.

> I am on Rails 2.02 and when I execute the followingRESTcall through
> curl:

> curl -H "Accept: application/json" -i -X GET
>http://localhost:3000/projects/3

> Then that's fine and I get the description of the project with the
> given ID.

> But if I do the following through curl:

> curl -X DELETEhttp://localhost:3000/projects/1

> I do get an error message that

> ActionController::InvalidAuthenticityToken

> exception caught

> what might be wrong about it?

Exactly what it says: the authenticity token is invalid, in your case it
is simply absent. This token is part of the new request forgery
protection. If it is enabled with protect_from_forgery (see the API
docs) then for all actions, except those using the HTTP GET method, a
token must be send as a query parameter. Inside your app, you can get
at the token with form_authenticity_token; I have no good idea what to
do to access the app from the commandline with curl or similar.

The problem is that the client being used does not work with cookies
by default. This is a totally reasonable and somewhat probable
solution in a RESTful service seeing as it is moving state (the
session/secret cookie saying who you are) out of the URL. A simple
client such as cURL can deal with cookies but should not have to.

In general, you have to request something from the app that includes the
authenticity token. It is automatically included in forms and in
destroy links.

I'm having the same problem. While I respect the need for it and do
not argue its value, it would be really helpful to see how to turn it
off. For example, I tried commenting out the
"config.action_controller.session" in my environment.rb but that
didn't work. I admit I'm new to Rails so that might have been a really
dumb way to go about it, so if other have better ideas including how
to grok some portion of the docs, it is very appreciated.

Eric,

The line is in the application.rb file. Mine looked like this:

class ApplicationController < ActionController::Base
  helper :all # include all helpers, all the time

  # See ActionController::RequestForgeryProtection for details
  # Uncomment the :secret if you're not using the cookie session store
  #protect_from_forgery # :secret => '*****'

Your secret will be different. In the original file, the
protect_from_forgery part wasn't commented out.

The application.rb file lives in your apps/controllers directory.

Good luck,
LG

Eric Larson wrote: