devise icon indicating copy to clipboard operation
devise copied to clipboard

DisabledSessionError when using authenticate_user! api only

Open mbackermann opened this issue 3 years ago • 21 comments

Pre Check

  • Create a new Rails 7 app rails new test_app --api
  • Add devise
  • run rails g devise:install
  • run rails g devise User
  • POST to /users and see the error stated below

Environment

  • Ruby 3.0.0
  • Rails 7.0.0
  • Devise 4.8.1

Current behavior

When using authenticate_user! on a controller on a rails API only app I am getting the following error: ActionDispatch::Request::Session::DisabledSessionError (Your application has sessions disabled. To write to the session you must first configure a session store):

Expected behavior

It should throw fail or success on warden depending on if the user is signed in or not.

mbackermann avatar Dec 21 '21 17:12 mbackermann

More context: Before Rails 7, the session passed to warden was a Hash. So even if the session was disabled, we were still able to write to the hash. Now, the session is an ActionDispatch::Session object, which is not writable on Rails API only apps, because the ActionDispatch::Session is disabled.

mbackermann avatar Dec 24 '21 19:12 mbackermann

I understand that Devise relies heavily on warden etc which rely on sessions, or a fake version of it at least. Thus, we've circumvented this by creating this concern/module that we have included in the relevant Devise-related controllers in our app:

module RackSessionFixController
  extend ActiveSupport::Concern

  class FakeRackSession < Hash
    def enabled?
      false
    end
  end

  included do
    before_action :set_fake_rack_session_for_devise
    
    private

    def set_fake_rack_session_for_devise
      request.env['rack.session'] ||= FakeRackSession.new
    end
  end
end

if the devise maintainers like it, we (AKA me or my team) can integrate this into Devise itself (E.g. allowing that logic to happen when API-mode is enabled) and expand the testsuite accordingly.

@carlosantoniodasilva WDYT ?

morenocarullo avatar Jan 11 '22 09:01 morenocarullo

@morenocarullo i use Rails.application.config.session_store :disabled and have the same Problem can you provide your FakeRakeSession Example?

arpu avatar Jan 22 '22 12:01 arpu

@arpu you need to drop that module I wrote in my earlier comment and include it in the SessionControllers. If @carlosantoniodasilva or other maintainer can suggest their acceptance, I can for sure make it included in devise itself so that it's automatic.

morenocarullo avatar Jan 24 '22 04:01 morenocarullo

reference rails change https://github.com/rails/rails/pull/42231

arpu avatar Jan 24 '22 13:01 arpu

I understand that Devise relies heavily on warden etc which rely on sessions, or a fake version of it at least. Thus, we've circumvented this by creating this concern/module that we have included in the relevant Devise-related controllers in our app:

module RackSessionFixController
  extend ActiveSupport::Concern

  class FakeRackSession < Hash
    def enabled?
      false
    end
  end

  included do
    before_action :set_fake_rack_session_for_devise
    
    private

    def set_fake_rack_session_for_devise
      request.env['rack.session'] ||= FakeRackSession.new
    end
  end
end

if the devise maintainers like it, we (AKA me or my team) can integrate this into Devise itself (E.g. allowing that logic to happen when API-mode is enabled) and expand the testsuite accordingly.

@carlosantoniodasilva WDYT ?

Thanks a lot for the help @morenocarullo.

I am using this resolution while the issue is not resolved

souzagab avatar Jan 29 '22 20:01 souzagab

Any update on when this will be fixed?

connortorrell avatar Jan 31 '22 23:01 connortorrell

@connortorrell you can use the solution posted here. I'm waiting for maintainers to say they'll accept the PR -- before it stays there forever

morenocarullo avatar Feb 01 '22 04:02 morenocarullo

Did they accept the PR?

NfoCipher avatar Feb 14 '22 08:02 NfoCipher

@NfoCipher I was waiting for an OK here to create the PR. BUT, since I got no answer ... I'll create the PR so that at least people can have a branch to point to, and will push to make it merged..

morenocarullo avatar Feb 15 '22 06:02 morenocarullo

Thank you @morenocarullo, using your fix as well. +1 for getting an official fix merged

KidA001 avatar Feb 15 '22 22:02 KidA001

FYI, I am preparing a PR for this issue. To begin with, we'll have a fork with the fix applied which is slightly better than the module-drop-in there, but I really want to make it upstream into the official branch.

morenocarullo avatar Feb 25 '22 10:02 morenocarullo

PR is here: https://github.com/heartcombo/devise/pull/5474

Feel free to use the referenced branch/fork while we wait for it to be merged.

morenocarullo avatar Feb 25 '22 13:02 morenocarullo

This: https://github.com/waiting-for-dev/devise-jwt/issues/235#issuecomment-1116864740 also seems to work.

NfoCipher avatar Jun 18 '22 01:06 NfoCipher

Hi, I am facing this error Minitest::UnexpectedError: ActionDispatch::Request::Session::DisabledSessionError: Your application has sessions disabled. To write to the session you must first configure a session store in testing environment. I am trying to do a simple assertion like

  test "should get index" do
    sign_in users(:one)
    get movies_url, as: :json
    assert_response :success
  end

but even having both workarounds (the one in application.rb and the other having RackSessionFix.rb) is not working.

Any ideas? Thanks.

VictorRubia avatar Dec 05 '22 10:12 VictorRubia

As described in https://github.com/wardencommunity/warden/blob/master/lib/warden/proxy.rb#L167 need to pass store: false to skip serializing into the session.

So adding

  def sign_up(resource_name, resource)
    sign_in(resource_name, resource, store: false)
  end

in your controller inherited from Devise::RegistrationsController should solve the problem

england avatar Dec 05 '22 14:12 england

In case this helps someone, you'll also need to pass in store: false for logging in.

This needs to be added to the controller inherited from Devise::SessionsController

  def auth_options
    super.merge({store: false})
  end

styliii avatar Dec 14 '22 16:12 styliii

Hi, any new about a fix ? Thx :)

This worked for me :

# application.rb

config.session_store :cookie_store, key: '_interslice_session'
    config.middleware.use ActionDispatch::Cookies
    config.middleware.use config.session_store, config.session_options

thibpoullain avatar Mar 02 '23 10:03 thibpoullain

No news :), but thanks for putting it into my radar again, I'll try to take a better look at the problem and the proposed solution(s) here. Thanks.

carlosantoniodasilva avatar Mar 02 '23 12:03 carlosantoniodasilva

Any reason this is still held up ?

sidevesh avatar Mar 16 '24 07:03 sidevesh