2

I'm having Rails web-app that has a form that pushes a request of a certain document into DB. A script on other machine should ask for newly created request. To handle that I've diced to add small JSON API inside the app.

For that purpose in routes I've added

  defaults format: :json do
    get "/api_name/get_request", to: "api_name#get_request"
  end

After that I've met CSRF problem. And after googling I've found out that I need to add protect_from_forgery unless: -> { request.format.json? } in my controller. It looks like the code as follows

class ApiNameController < ApplicationController
  protect_from_forgery unless: -> { request.format.json? }

  def get_request
    render json: {message: 'Received'}, status: :ok
  end
end

After that in log I have

Started GET "/api_name/get_request" for ::1 at 2018-02-05 16:43:08 +0300
Processing by ApiNameController#get_request as JSON
  Parameters: {"api_name"=>{}}
Completed 401 Unauthorized in 5ms (ActiveRecord: 0.0ms)

So the problem is still there. The questions are

  1. What should I do to solve the problem?
  2. Allowing JSON requests from any origin seem to be dangerous. How can I ad some protection? Maybe I should send some header from remote machine and check it inside verified_request ?

UPD I've changed comment inside get_request with render json: {message: 'Received'}, status: :ok and after that the result is the same

4
  • what do u have in application_cntr..? Commented Feb 5, 2018 at 14:05
  • This is a 401 response, which suggests a different error. In my apps CSRF errors return 422 status. Are you using Devise or another authentication system? Also, have you tried boosting your log level to debug Commented Feb 5, 2018 at 14:08
  • @Phil, yes I have before_action :authenticate_user!, :unless => :devise_controller? in app controller Commented Feb 5, 2018 at 14:16
  • if u need an authentication actions, let me know i can update the post... Commented Feb 5, 2018 at 14:31

2 Answers 2

2

You have to skip devise before_actions, if its assigned in ApplicationController.

Controllers:

class ApiController < ApplicationController
   protect_from_forgery unless: -> { request.format.json? }
   skip_before_action :authenticate_user!, only: :get_request

   def get_request
      render json: {message: 'Received'}, status: :ok
   end

end

Routes:

namespace :api, defaults: { format: :json } do
   get 'get_request' => 'api#get_request'
end

To handle cross origin:

Rack Cors Gem Link

Rack Attack Gem Link

Sign up to request clarification or add additional context in comments.

Comments

1

You probaly have some web authentication in ApplicationController in before_filter, since your ApiNameController inherits from it. That's why you receive Unauthorized response. So you should either stop inheriting from it, or exclude api controller methods from web-auth before-hook with some sort of:

class ApiNameController < ApplicationController
  skip_before_action :authenticate_user!, only: :get_request

Speaking of security, you have at least two options:

The last one is less secure than token-based auth, but it's easier to implement, so it's up to you which one to chose.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.