Invalid Authenticity Token on Post - ruby-on-rails

I am using devise to sign up/in.
routes
get 'profile' => 'profile#get_profile'
post 'profile' => 'profile#create_profile'
and profile_controller
def get_profile
render json: {user: current_user}, status: :ok
end
def create_profile
render json: {user: current_user}, status: :ok
end
GET: http://localhost:3000/user/profile returns the expected output. However,
POST request throws an error saying:
ActionController::InvalidAuthenticityToken in User::ProfileController#create_profile.
Please demystify this behavior.

To disable CSRF protection you can edit your ApplicationControllerlike this:
class ApplicationController < ActionController::Base
protect_from_forgery with: :null_session
# ...
end
or disable the CSRF protection for specific controller:
class ProfilesController < ApplicationController
skip_before_action :verify_authenticity_token
# ...
end
:null_session strategy empties the session instead of raising an exception which is perfect for an API. Because the session is empty, you can't use current_user method or othes helpers that refer to the session.
IMPORTANT:
protect_from_forgery with: :null_session must be used only in specific
cases, for example to allow API request (POST/PUT/PATCH/DELETE) without html form
With protect_from_forgery with: :null_session you must restrict access to your data with an authorization system because every one could do request against your API endpoint
Don't remove protect_from_forgery with: :exception for requests that are done through html form, is dangerous! (read here http://guides.rubyonrails.org/security.html#cross-site-request-forgery-csrf)
To handle both standard requests (through html form) and API requests generally you have to set up two different controller for the same resource. Example:
Routes
Rails.application.routes.draw do
resources :profiles
namespace :api do
namespace :v1 do
resources :profiles
end
end
end
ApplicationController
# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
end
ProfilesController
(standard controller for html requests)
# app/controllers/profiles_controller.rb
class ProfilesController < ApplicationController
# POST yoursites.com/profiles
def create
end
end
Api::V1::ProfilesController
(controller for API requests)
# app/controllers/api/v1/profiles_controller.rb
module Api
module V1
class ProfilesController < ApplicationController
# To allow only json request
protect_from_forgery with: :null_session, if: Proc.new {|c| c.request.format.json? }
# POST yoursites.com/api/v1/profiles
def create
end
end
end
end
refereces:
http://api.rubyonrails.org/classes/ActionController/RequestForgeryProtection/ClassMethods.html#method-i-protect_from_forgery

Get requests don't have an authenticity token.
You will have to add the request forgery stuff to your forms using this
<%= csrf_meta_tag %>
And address via javascript
$('meta[name="csrf-token"]')

In ApplicationController (or another controller your controllers inherit from) there's a line:
protect_from_forgery with: :exception
Remove it and CSRF checks will be disabled.

Related

Devise and Devise Token Auth

I am trying to make rails web app along with rails API for mobile app. For this purpose I am using Devise along with Devise token auth.
I configured routes as it is written in Devise token auth gem so as I could have routes for regular Devise and Devise auth token.
I have 2 problems:
When I add include DeviseTokenAuth::Concerns::SetUserByToken to application_controller it overwrites Devise authenticate_user! and on web side I am being aunthenticated with token.
Possible solution: I created separet ApiApplicationController from which API controllers inherit.
class ApiApplicationController < ActionController::Base
include DeviseTokenAuth::Concerns::SetUserByToken
protect_from_forgery with: :null_session
end
For each POST request which I do in curl to my API I need to add CSRF token.
Possible solution: I could add to both ApplictionController and ApiApplicationController if: Proc.new { |c| c.request.format == 'application/json' } after protect_from_forgery with: :null_session
I used to get the same problem to yours, my solution which is currently working:
# application_controller.rb
class ApplicationController < ActionController::Base
protect_from_forgery with: :null_session, if: ->{request.format.json?}
end
# api_application_controller.rb
class ApiApplicationController < ActionController::Base
include DeviseTokenAuth::Concerns::SetUserByToken
before_action :authenticate_user!
end

Shopify / Rails App: Where do I call a method that I want to run immediately after installation?

I've built a Shopify app on Rails using shopify_app gem. I want to call a method immediately after a store owner installs the app, but I'm having trouble figuring out where I would call that.
What is the controller#action when a new instance of the app is created?
I have
class ApplicationController < ActionController::Base
include ShopifyApp::Controller
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
end
class AuthenticatedController < ApplicationController
before_action :login_again_if_different_shop
around_filter :shopify_session
layout ShopifyApp.configuration.embedded_app? ? 'embedded_app' : 'application'
end
class HomeController < AuthenticatedController
def index
#customers = ShopifyAPI::Customer.find(:all, :params => {:limit => 100})
end
end
class SessionsController < ApplicationController
include ShopifyApp::SessionsController
end

auth protected pages in rails 4 application how to

I'm getting a redirect loop. I have a clear idea why, user is logged out, redirected to login page (welcome#index) and user is still logged out and we have an endless loop.
How do I get out of loop?
I read about several options.
before_action :require_login placing it inside controllers where login is required. EASY, but a lot of copy paste, we love dry don't' we?
except, before_action :require_login, :except => root? I couldn't find details about except. I'm getting a lot of hits on before_filter which seems to be deprecated.
skip_before_action same here, I can only find bits and pieces :(
There should be a better way to handle these, is it rails way to do check routes level in config/routes.rb?
Application controller:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
helper_method :current_user
before_action :require_login
private
def current_user
#current_user ||= Dedit::User.find(session[:user_id]) if session[:user_id]
end
private
def require_login
redirect_to root_path unless current_user.present?
end
end
login page controller:
class WelcomeController < ApplicationController
layout 'basic'
def index
if current_user.present? then redirect_to dedit_path end
end
end
before_action :require_login, except: [:index]

Rails 4: Redirect Loop with before_filter

I am setting up a very simple rails app that involves a simple authentication check before you can enter the site. But, when the before_filter runs, and the user is redirected to the login path, a redirect loop occurs.
ApplicationController:
class ApplicationController < ActionController::Base
# Prevent CSRF attacks by raising an exception.
# For APIs, you may want to use :null_session instead.
protect_from_forgery with: :exception
before_filter :check_session
private
def check_session
redirect_to login_path and return unless current_user?
end
def current_user?
!session[:username].blank?
end
end
SessionsController
class SessionsController < ApplicationController
def new
end
end
The issue is that, since your SessionsController inherits from ApplicationController, it actually inherits the before_filter as well. This means you are not allowing someone to see the login page unless they are logged in, which is usually undesirable behavior. You want to skip this before_filter on the login page:
class SessionsController < ApplicationController
skip_before_filter :check_session, only: :new
def new
end
end
I think you have problem in your routes. One way of solution is defining a root path for your app as:
root 'app_entry#index'
Then create a controller for it as given below:
class AppEntryController < ApplicationController
def index
if current_user
redirect_to 'controller_name/action_name'
else
redirect_to '/users/sign_in'
end
end
Hope this helps you.
You should use the before filter like this
before_filter :check_session, :except => [:new]

Why is Rails redirecting my POST but not GET?

I'm trying to post data to a certain controller#action pair, but my app redirects me on POST (but not GET), and I can't figure out why.
I built a bare-bones controller with one method:
class NavigationsController < ApplicationController
def foo
render :text => 'in foo'
end
end
My routing file has only one rule:
map.connect ':controller/:action/:id'
Here's my result when I GET and POST, though:
$ curl http://localhost:3000/navigations/foo/1
in foo
$ curl -d 'a=b' http://localhost:3000/navigations/foo/1
<html><body>You are being redirected.</body></html>
specs: rails 2.3.8, ruby 1.8.7
Turn off protect_from_forgery.
For all controllers
Commenting out (or delete) protect_from_forgery in ApplicationController.
class ApplicationController < ActionController::Base
#protect_from_forgery # See ActionController::RequestForgeryProtection for details
# ...
end
For one or more controllers
Add skip_before_filter :verify_authenticity_token to the controller declaration.
class NavsController < ApplicationController
skip_before_filter :verify_authenticity_token
# ...
end
For one or more actions
Add an :except option to the foregoing skip_before_filter or protect_from_forgery commands.
class MyController < ApplicationController
protect_from_forgery :except => :index
end
class MyOtherController < ApplicationController
skip_before_filter :verify_authenticity_token, :except => [:create]
end

Resources