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

asked Feb 5, 2018 at 13:56
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

answered Feb 5, 2018 at 14:26
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.

answered Feb 5, 2018 at 14:15

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

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.