Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

InvalidAuthenticityToken in Devise::SessionsController#destroy (sign out after already having signed out)

I am using Devise 3.2.0 for authentication and found an issue when I do the following:

  • tab 1: sign in to app
  • tab 2: go to any page in the app
  • tab 2: sign out (success)
  • tab 1: sign out (failure - see exception below)

Exception raised:

ActionController::InvalidAuthenticityToken in Devise::SessionsController#destroy

In the development log I see:

Can't verify CSRF token authenticity

And the top three lines of the stack trace are:

ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken):
  actionpack (4.0.0) lib/action_controller/metal/request_forgery_protection.rb:163:in `handle_unverified_request'
  actionpack (4.0.0) lib/action_controller/metal/request_forgery_protection.rb:170:in `handle_unverified_request'
  devise (3.2.0) lib/devise/controllers/helpers.rb:198:in `handle_unverified_request'

How can I ensure successive sign outs don't raise an exception?

like image 918
user664833 Avatar asked Mar 18 '14 17:03

user664833


5 Answers

paste this in the layout: <%= csrf_meta_tags %>

like image 148
vidur punj Avatar answered Nov 13 '22 10:11

vidur punj


A simple solution to this problem could also be allowing sign outs via GET rather than DELETE. In devise.rb you can simply change to:

# The default HTTP method used to sign out a resource. Default is :delete.
config.sign_out_via = :get
like image 27
Peleg Avatar answered Nov 13 '22 09:11

Peleg


Here is whats happening,

When you initially signed out from tab 2, session and authenticity_token associated with the logged in user was destroyed. When you try to sign out from tab 1, Devise again tries to destroy the session using the authenticity_token which was destroyed on tab 2.

Hence, you get the error ActionController::InvalidAuthenticityToken as devise fails to authenticate using the given authenticity_token.

You only get one unique session per sign in, if that gets destroyed you'll have nothing to destroy again.

EDIT

This behavior is not provided by Devise. If you wish to implement such behavior you will have to override SessionsController.

Create a sessions_controller.rb file in app/controllers/users directory

class Users::SessionsController < Devise::SessionsController
  prepend_before_filter :verify_user, only: [:destroy]

  private
  ## This method intercepts SessionsController#destroy action 
  ## If a signed in user tries to sign out, it allows the user to sign out 
  ## If a signed out user tries to sign out again, it redirects them to sign in page
  def verify_user
    ## redirect to appropriate path
    redirect_to new_user_session_path, notice: 'You have already signed out. Please sign in again.' and return unless user_signed_in?
  end
end

Update routes.rb

devise_for :users, :controllers => { :sessions => "users/sessions" }
like image 12
Kirti Thorat Avatar answered Nov 13 '22 11:11

Kirti Thorat


If you are still having this issue as i did in Rails 5 and devise 4.4.1, in the app/controllers/application_controller.rb change

protect_from_forgery with: :exception

to

protect_from_forgery with: :null_session

hope it helps.

like image 3
Frank Etoundi Avatar answered Nov 13 '22 09:11

Frank Etoundi


You can change strategy of verify csrf token.

In rails 3 the default strategy when verify is failed, is return a null session. In rails 4 was changed the strategy in application_controller to return a exception.

I solve this, changing in my application_controller.rb

class ApplicationController < ActionController::Base
-    protect_from_forgery, with: :exception
+    protect_from_forgery

This way, use the default strategy.

like image 1
Nícolas Lazarte Kaqui Avatar answered Nov 13 '22 09:11

Nícolas Lazarte Kaqui