InvalidAuthenticityToken in Devise - ruby-on-rails

I recently added a piece of code to my ApplicationController to set the timezone of the current block to the one specified by the user.
class ApplicationController < ActionController::Base
around_action :set_time_zone, if: :current_user
protect_from_forgery with: :exception
private
def set_time_zone(&block)
Time.use_zone(current_user.time_zone, &block)
end
end
For some reason when I try to sign in i get a
ActionController::InvalidAuthenticityToken in Devise::SessionsController#create
If i remove
around_action :set_time_zone, if: :current_user
I can sign in and if i add it back after I sign in, everything works as expected.
Any ideas?

This page has good info on the problem, but I was weirdly able to fix this in Rails 5 by putting protect_from_forgery above the around_action/filter. Hope it helps!

Related

alias_method': undefined method `current_user'

Hi i tried to implement forest_admin gem in rails 5 application
When i generate install with this command
rails g forest_liana:install <ENVIRONMENT SECRET>
The logs are alias_method': undefined method current_user' for classApplicationController' (NameError)
My aplication Controller
class ApplicationController < ActionController::Base
skip_before_action :verify_authenticity_token
before_action :session_expirada, unless: :devise_controller?
before_action :set_attr_to_current_user, unless: :devise_controller?
layout :layout_by_resource
alias_method :devise_current_user, :current_user
include RedirectFromEmail
# Pundi Authorization filtros
include Pundit
#after_action :verify_authorized, unless: :devise_controller? , #except: :index
#to catch message error Pundit
rescue_from Pundit::NotAuthorizedError, with: :user_not_authorized
end
What happend?
You are trying to alias the method ":devise_current_user" to ":current_user". IN your controller current_user is not defined. If you define current_user in your controller(see below) then you will not get this error.
def current_user
#logic to get a handle on current user goes here
end
Remove alias and just use regular devise current_user which is included by default

Intermittent Rails 5 ActionController::InvalidAuthenticityToken

Context: a Rails app in production, hosted on Heroku, that has around 800 users.
Ruby 2.4.2
Rails 5.1.4
Devise 4.3.0
For some reason, I have seen a few users experience an error:
ActionController::InvalidAuthenticityToken
[GEM_ROOT]/gems/actionpack-5.1.4/lib/action_controller/metal/request_forgery_protection.rb:195
For requests to POST /students/:id/registrations.
It is intermittent, and very few users experience the error.
Clients are Safari 11.0 on iPads.
ApplicationController:
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
before_action :authenticate_user!, unless: :devise_controller?
before_action :restrict_from_students, unless: :devise_controller?
# ...
end
RegistrationsController:
class RegistrationsController < ApplicationController
skip_before_action :restrict_from_students, only: :create
# ...
end
Is there some scenario (re-POSTing the request, auth timeout but submitting, lack of JS) that would cause this? I cannot seem to reproduce it.
I was having a similar issue.
Use rescue_from in the application controller and redirect somewhere useful with a notification. In my case I attempt to redirect the user back to where they were to reattempt their action, or to the home page as a fallback.
Example for rails 5:
class ApplicationController < ActionController::Base
rescue_from ActionController::InvalidAuthenticityToken,
with: :handle_invalid_token
def handle_invalid_token
redirect_back fallback_location: root_path,
notice: 'Stale session detected'
end
end
Thanks to the rubber duck, I have reproduced the issue.
Sign out
Go "back" to the cached app UI.
Click the button to generate a POST request.
Observe the exception.
The solution here is to use rescue_from to likely redirect the user to the sign in page.
Thank you rubber duckie!

Shouldn't protect_from_forgery with: :exception raise an error if I don't include an authenticity token?

It's my understanding that protect_from_forgery with: :exception which is the default in Rails, will cause an error if forms are submitted and they don't have the authenticity_token input.
However it seems like this is not the case anymore. This is a Rails 5 app, and I've mostly done Rails 4 in the past, so I wonder if something has changed.
In application_controller.rb I have protect_from_forgery with: :exception
My form is like this (using slim)
form#spreadsheet-form{
action='/submit_spreadsheet'
}
textarea.spreadsheet-input{
name='instructions'
style="width: 200px; height: 200px"
}
br
input.spreadsheet-submit{
type="submit"
value="submit"
}
The main issue in my eyes is why this doesn't raise an error. In the past I've had to include a hidden input with form_authencicity_token as the value.
I believe it is something to do with the Rails 5 changed the protect_from_forgery execution order. From this blog
What
If we generate a brand new Rails application in Rails 4.x then application_controller will look like this.
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
end
Looking it at the code it does not look like protect_from_forgery is a before_action call but in reality that’s what it is. Since protect_from_forgery is a before_action call it should follow the order of how other before_action are executed. But this one is special in the sense that protect_from_forgery is executed first in the series of before_action no matter where protect_from_forgery is mentioned. Let’s see an example.
class ApplicationController < ActionController::Base
before_action :load_user
protect_from_forgery with: :exception
end
In the above case even though protect_from_forgery call is made after load_user, the protection execution happens first. And we can’t do anything about it. We can’t pass any option to stop Rails from doing this.
Rails 5 changes this behavior by introducing a boolean option called prepend. Default value of this option is false. What it means is, now protect_from_forgery gets executed in order of call. Of course, this can be overridden by passing prepend: true as shown below and now protection call will happen first just like Rails 4.x.
class ApplicationController < ActionController::Base
before_action :load_user
protect_from_forgery with: :exception, prepend: true
end
Why
There isn’t any real advantage in forcing protect_from_forgery to be the first filter in the chain of filters to be executed. On the flip side, there are cases where output of other before_action should decide the execution of protect_from_forgery. Let’s see an example.
class ApplicationController < ActionController::Base
before_action :authenticate
protect_from_forgery unless: -> { #authenticated_by.oauth? }
private
def authenticate
if oauth_request?
# authenticate with oauth
#authenticated_by = 'oauth'.inquiry
else
# authenticate with cookies
#authenticated_by = 'cookie'.inquiry
end
end
end
Above code would fail in Rails 4.x, as protect_from_forgery, though called after :authenticate, actually gets executed before it. Due to which we would not have #authenticated_by set properly.
Whereas in Rails 5, protect_from_forgery gets executed after :authenticate and gets skipped if authentication is oauth
Is the authenticity token present on your form when you inspect it? Which point is protect_from_forgery inserted in your application?
Rails 4=>5 changed the default behaviour to be inserted wherever in the chain it is called, opposed to the previous where it was called first. If you want it to be called before any other action, try using the prepend: true flag.

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]

Resources