3

On my react frontend, I have an API request which is being sent to my ruby on rails backend, via the axios library:

        Axios({
            url: "/terms",
            headers: {
                'Authorization': token
            }
        }).then((response) => {
            console.log(response.request)
            setActiveSet(response.data)
            setActiveSetIndex(0)
        }).catch((error) => {
            console.log(error)
        })

When the above request is performed, I see the following chain of responses in my backend logs (ruby on rails):

Started GET "/terms" for 192.168.1.119 at 2021-01-05 13:54:02 -0700
Cannot render console from 192.168.1.119! Allowed networks: 127.0.0.0/127.255.255.255, ::1
Processing by TermsController#index as HTML
Completed 401 Unauthorized in 0ms (ActiveRecord: 0.0ms | Allocations: 491)


Started GET "/users/sign_in" for 192.168.1.119 at 2021-01-05 13:54:02 -0700
Cannot render console from 192.168.1.119! Allowed networks: 127.0.0.0/127.255.255.255, ::1
Processing by Devise::SessionsController#new as JSON
Completed 200 OK in 1ms (Views: 0.2ms | ActiveRecord: 0.0ms | Allocations: 907)


Started GET "/terms" for 192.168.1.119 at 2021-01-05 13:54:02 -0700
Cannot render console from 192.168.1.119! Allowed networks: 127.0.0.0/127.255.255.255, ::1
Processing by TermsController#index as HTML
Completed 401 Unauthorized in 1ms (ActiveRecord: 0.0ms | Allocations: 491)


Started GET "/users/sign_in" for 192.168.1.119 at 2021-01-05 13:54:02 -0700
Cannot render console from 192.168.1.119! Allowed networks: 127.0.0.0/127.255.255.255, ::1
Processing by Devise::SessionsController#new as JSON
Completed 200 OK in 1ms (Views: 0.2ms | ActiveRecord: 0.0ms | Allocations: 905)

The .catch block is never called. When I look at the responses, I see 2 successful 200 responses. The 401 responses don't show up on the frontend.

I'm trying to capture the 401 status code, and then display a login form to the user via my react frontend. The backend (devise gem) is trying to redirect me to /users/sign_in, which is not what I want to happen. I just want a 401 so that my react app can display its own login form, but for reasons unknown to me, axios is only showing the response having 200 statuses.

Blaine Lafreniere
  • 3,451
  • 6
  • 33
  • 55

2 Answers2

1

You can modify the responses when authentication fails by changing the failure app:

module MyNamespace
  class FailureApp < Devise::FailureApp
    def respond
      request.format.json? ? api_response : super
    end

    private
    def api_response
      self.status = 401
      self.content_type = 'application/json'
      # optional - send a message in the response body
      # response.body = { error: i18n_message }.to_json
    end
  end
end
# add to config/initializers/devise.rb
config.warden do |manager|
  manager.failure_app = MyNamespace::FailureApp
end

The failure app is just a basic Rack application built on ActionController::Metal that gets called when Warden throws (when user authentication fails).

max
  • 96,212
  • 14
  • 104
  • 165
0

You can add Accept: application/json header to your request. For JSON requests the redirect to the sign in page is not performed.

With your example:

        Axios({
            url: "/terms",
            headers: {
                'Authorization': token,
                'Accept': 'application/json'
            }
        }).then((response) => {
            console.log(response.request)
            setActiveSet(response.data)
            setActiveSetIndex(0)
        }).catch((error) => {
            console.log(error)
        })

You'll see that your Rails app just returns 401 with no redirects.

senya
  • 984
  • 12
  • 20