user3920567
user3920567

Reputation: 91

use protect_from_forgery with: :exception but redirect user to login page if session expired

I have a Rails application with login function which I have protect_from_forgery with: :exception set on application_controller.rb.

I had encountered a problem where some user had been shown the exception page when they do the following actions:

  1. Open two tabs with a browser to the login screen.
  2. Log in using the first tab and then log out.
  3. Switch to the second tab and then proceeding to log in.
  4. The second tab resulted in exception screen due to the reason that session cookies already changed because the user had logged in and logged out with another tab.

I also consider changing protect_from_forgery with: :exception to protect_from_forgery with: :reset_session but it will allow CSRF attack which mentioned in this site: https://rubyplus.com/articles/4921-Rails-Forgery-Protection-Basics

I am wondering how other rails application tackles this problem.

Upvotes: 3

Views: 649

Answers (1)

MatayoshiMariano
MatayoshiMariano

Reputation: 2096

You can try a couple of things here:

1) Rescue the exception:

rescue_from ActionController::InvalidAuthenticityToken do
  render text: 'Token expired/invalid' # Or render whatever you want :)
end

2) Override handle_unverified_request in you Application controller:

def handle_unverified_request
  flash[:alert] = 'You have already signed out or the session has expired. Please sign in again.'
  # Store the current url so at after_sign_in_path_for it grabs this URL and not the new_user_session_path
  store_location_for(:user, request.fullpath) # This is if you're using devise. It just store the last URL the user visited
  redirect_to new_user_session_path # Redirect to the sign in path
end

3) Or just use a prepend_before_action in your ApplicationController:

prepend_before_action :verify_user!, unless: :user_signed_in?

def verify_user!
  flash[:alert] = 'You have already signed out or the session has expired. Please sign in again.'
  # Store the current url so at after_sign_in_path_for it grabs this URL and not the new_user_session_path
  store_location_for(:user, request.fullpath)# This is if you're using devise. It just store the last URL the user visited
  redirect_to new_user_session_path # Redirect to the sign in path
end

Hope it helps! :)

Upvotes: 0

Related Questions