I'm building a ruby API using rails admin (which is working) and rails admin import which has this problem:
Can't verify CSRF token authenticity.
Tried to deactivate it with
module Api::V1
class ApiController < ApplicationController
skip_before_action :verify_authenticity_token
...
class ApplicationController < ActionController::API
skip_before_action :verify_authenticity_token
But the result was the same error. Any ideas?
Thank you
P.S:
Also getting this when I put the code above(as it apears not to be implemented)
"status":500,"error":"Internal Server Error"
"exception":"# ArgumentError: Before process_action callback :verify_authenticity_token has not been defined"
How did you setup rails_admin?
Did you try using different controllers for both API and RailsAdmin, adding the needed includes in the later? Namely including ActionController::RequestForgeryProtection as described in Using rails_admin with rails_api?
Related
I understand why rails defaults to disabling CSRF protection on GET requests, but I have an edgecase where this is required. Is there a way to do this in rails?
I think you can do it in the following way in your controller.
class FooController < ApplicationController
protect_from_forgery
end
I am trying to implement both devise_token_auth and Active Admin in my rails api back-end.
There are pretty clear instructions on the devise_token_auth FAQ explaining how to implement the two together - it requires two different Application Controller classes.
# app/controllers/api_controller.rb
# API routes extend from this controller
class ApiController < ActionController::Base
include DeviseTokenAuth::Concerns::SetUserByToken
end
# app/controllers/application_controller.rb
# leave this for ActiveAdmin, and any other non-api routes
class ApplicationController < ActionController::Base
end
I have both of these controllers in my app, but I can't figure out how to inherit from them for the controllers for Active Admin and devise_token_auth.
I'm sure I am missing something basic here, because in all of the answers that I've seen about this on StackOverflow, it seems assumed that I know how to do this.
Can anyone help?
Edit:
Restating the problem, because I don't think I was clear the first time. Right now, both Active Admin and devise_token_auth are using the ApplicationController, even though I created the ApiController too. How do I make devise_token_auth use the ApiController?
You can definitely use a separate namespace, that will make your code cleaner and better organized. However it is not mandatory. All you need to do is in your controllers for the APIs, extend your ApiController instead of ActionController::Base.
For example, here's a base API controller,
class Api::V1::BaseController < ActionController::API
include DeviseTokenAuth::Concerns::SetUserByToken
include Pundit
end
and a sample controller that extends it and uses devise_token_auth as a result.
class Api::V1::SampleController < Api::V1::BaseController
def index
render json: { success: true, email: current_user.email }, status: :ok
end
end
Here's a sample project that has separate web and API controllers https://github.com/anujmiddha/rails-api-web-sample
you can refer to devise_token_auth demo example in devise_token_auth's readme on github.
the main difference between your case and the demo app is that you will use ApiController instead of ApplicationController. also, you have to add devise_token_auth attributes to the corresponding model, (for example, if you want to use devise_token_auth with users, you have to add the attributes to the users table and before_action: authenticate_user! to UsersController.).
I have a Rails application where I'm using Vue (through webpacker) in some parts of the frontend.
From Vue I'm making a call to my server which needs to access the current_user (Devise), however, I'm getting the Can't verify CSRF token authenticity. error and the current user is not returned.
To avoid this I skipped the before_action like so:
skip_before_action :verify_authenticity_token, only: :stripe_vue
def stripe_vue
...
end
However, I'm still getting exactly the same issue.
It's kind of weird as I'm doing exactly the same thing in another controller and it works like charm.
Comment this line
protect_from_forgery with: :exception
and final code should look like this
skip_before_action :verify_authenticity_token
#protect_from_forgery with: :exception
I am working on a Rails 5 api project which is used by mobile client with gem devise_token_auth for authorization.
I am clear about what the warning means.
1st Question: CSRF protect should be turned OFF for api(JSON/XML)respond, correct?
I searched some on web it seems CSRF just happens on web application with cookie. But i read this from rails api document:
It's important to remember that XML or JSON requests are also affected >and if you're building an API you should change forgery protection >method in ApplicationController (by default: :exception):
class ApplicationController < ActionController::Base
protect_from_forgery unless: -> { request.format.json? }
end
So i still get the warning by adding like this:
class ApplicationController < ActionController::Base
protect_from_forgery unless: -> { request.format.json? }
include DeviseTokenAuth::Concerns::SetUserByToken
end
2nd Question: If API doesn't need CSRF protection, why
protect_from_forgery unless: -> { request.format.json? }
doesn't work?
Not sure if i understood something wrong. Thank you!
the code should be:
protect_from_forgery with: :null_session, if: ->{request.format.json?}
You might have to use null_session for API, it provides an empty session during request but doesn't reset it completely. Used as default if :with option is not specified.
I want to build a rails app with two different protect_from_forgery strategies: one for the web application, and one for the API.
In my application controller I have this line of code: protect_from_forgery with: :exception in order to prevent CSRF attacks, it works just fine.
In my API namespace, I created an api_controller that inherits from my application controller, and that is the parent class of all the other controllers in the API namespace, and I changed the code above with: protect_from_forgery with: :null_session.
Sadly, I have an error when trying to make POST request: "Can't verify CSRF token authenticity".
I don't want to skip the verify_authenticity_token method in my API controllers, I just want to have two distinct strategies in my app, so how do I override the protect_from_forgery strategy defined in my application controller ?
Edit: Ok, so I eventually did what I did not want to do in the first place: change the inheritance of my api_controller: it now inherits from ActionController::Base, and no longer from my application controller. It does work now but:
It does not answer my question i.e. overriding the protect_from_forgery strategy.
It is not DRY as I have to copy/past what was previously in my application_controller.
So if anyone has a real way to overwrite this method, I'd appreciate it.
What if you leave the protect_from_forgery with: :exception in the application controller but then you put the following in your API controller?
skip_before_action :protect_from_forgery
protect_from_forgery with: :null_session
That way, you still get the standard CSRF attack protection for all controllers in your web application but you also get the null session behavior for your API methods.
I am running an application with a similar structure - Web App + API. I solved the CSRF problem like this:
Apply protect_from_forgery only for non API requests
My API endpoint is api.example.com, so I used subdomain constraint to distinguish API and web app requests
Code:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception, if: :isWebRequest?
def isWebRequest?
request.subdomains[-1] != 'api'
end
end
Late to the party, but something like this can be done:
class YourCustomStrategy
def initialize(controller)
end
def handle_request
end
end
And in your ApplicationController or where you want:
class ApplicationController < ActionController::Base
protect_from_forgery with: YourCustomStrategy
end