heartcombo / devise

Flexible authentication solution for Rails with Warden.
http://blog.plataformatec.com.br/tag/devise/
MIT License
23.89k stars 5.54k forks source link

http_authenticatable_on_xhr and request.xhr? check are always false these days #5593

Open dleavitt opened 1 year ago

dleavitt commented 1 year ago

Environment

Current behavior

I add the following to my devise configuration:

config.http_authenticatable = true
config.http_authenticatable_on_xhr = false

When making a request

The response contains the "WWW-Authenticate" header, which triggers a basic auth prompt in my browser.

Expected behavior

Because I have http_authenticatable_on_xhr set to false, I should not receive any prompt, just a 401 error that my javascript can then handle.

Problem / Solution

Devise uses Rack::Request#xhr? to decide whether a request is xhr / "ajax" or not. Rack in turn uses the value of the X-Requested-With HTTP header, which is not set by fetch or either of the two request libraries I looked at (axios, apollo client.)

I don't think it's a very useful way, as of 2023, to detect whether a request was initiated from javascript.

However, this detection seems non-trivial and maybe not something devise wants to be in the business of, so the shape of a good solution might be:

Happy to look into this a bit more and submit a PR!

Workarounds

  1. Use a custom failure app:

# lib/my_failure_app.rb
class MyFailureApp < Devise::FailureApp
  # Force devise not to send the WWW-Authenticate header (which pops up a
  # basic auth prompt) on fetch requests (or ever.)
  def http_auth_header?
    false
  end
end

# config/initializers/devise.rb
require "devise/my_failure_app"
Devise.setup do |config|
  # ...
  config.warden do |manager|
    manager.failure_app = MyFailureApp
  end
  # ...
end
  1. Maybe: Add X-Requested-With: XMLHttpRequest header to outgoing HTTP requests from javascript.