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
- What should I do to solve the problem?
- 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
2 Answers 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:
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.
application_cntr..
?before_action :authenticate_user!, :unless => :devise_controller?
in app controller