Search code examples
ruby-on-railsrubyhttpruby-on-rails-3authenticity-token

How to handle the AuthenticityToken value using a HTTP POST request from a RoR application to another RoR application?


I am using Ruby on Rails 3 and I would like to know how to handle the AuthenticityToken value using a HTTP POST request from a RoR application to another RoR application. In this case I aim to submit a sign in form and return the user information in JSON format if he\she provided correct email and password values.

I have a RoR application at this URL

pjtnam.com

and another RoR application at this URL

users.pjtname.com

If I make an HTTP POST request from the application pjtname.com to the application users.pjtname.com like this (in this example I use the Typhoeus gem)

response = Typhoeus::Request.post("http://users.pjtname.com/authentications",
             :params => {
               :new_authentication => {
                 :email    => email,
                 :password => password
               }
             }
           )

I get this response

<h1>
  ActionController::InvalidAuthenticityToken
    in AuthenticationsController#create
</h1>
<pre>ActionController::InvalidAuthenticityToken</pre>

So, how to handle the AuthenticityToken value in a safe approach\mode? I would like to know in both when applications are located on the same server and when they aren't.

At http://users.pjtname.com/authentications/new I have the following form for signing in users:

<%= form_for(:new_authentication) do |f| %>
  <%= f.label :email %>
  <%= f.label :password %>

  <%= f.submit "Sign in" %>
<% end %>

In the authentications_controller.rb I have

def create
  # Note ':authentication' symbol is different than ':new_authentication' seen in HTTP POST parameters and in the above form
  @authentication = Authentication.new(params[:authentication])

  @account = Account.sign_in_account(params[:new_authentication][:email], params[:new_authentication][:password])

  ...

  respond_to do |format|
    format.html {
      redirect_to @account
    }
    format.js {
      render(:update) { |page|
        page.redirect_to @account
      }
    }
    format.json {
      render :json => @account
    }
  end
end

In routes.rb I have

  resources :authentications do #, :path => "authentication" do
    member do
      get  'confirm_authentication'
      post 'confirm_authentication'
    end
  end


UPDATE for the @idlefingers answer


REQUEST

Typhoeus::Request.post("http://users.pjtname.com/authentications/new",
# or
# Typhoeus::Request.post("http://users.pjtname.com/authentications",
   :headers => {"Content-Type" => "application/json"},
   :params => { ... } # Same parameters as above
   }
 )

RESPONSE

<h1>
  StandardError
</h1>
<pre>Invalid JSON string</pre>

REQUEST

Typhoeus::Request.post("http://users.pjtname.com/authentications/new.json",
   :params => { ... } # Same parameters as above
   }
 )

RESPONSE

<h1>Routing Error</h1>
<p><pre>No route matches &quot;/authentications/new.json&quot;</pre></p>

Solution

  • It looks like it's not sending the request with the correct content type. Rails should skip the authenticity token check if the content-type is application/xml or application/json, so that it plays nice with APIs without having to disable the authenticity token altogether.

    I don't know the Typhoeus gem, but it looks like you may need to just add ".json" or ".xml" to the url (depending on the API you've implemented), or may need to pass it in as options in the headers hash.