I'm using Rails 6 in API mode and the latest version of devise.
I created rspec test for sign_in and sign_up and it works correctly they accept json answer and respond in json
When I try to test my API with postman it work for sign_up but not for sign_in.
With postman I got the following return
{
"sucess": false,
"message": "fail myapp_failure_app"
}
So I try to dig in the devise gem
the problem and I finally found out the problem is here
def create
self.resource = warden.authenticate!(auth_options)
...
end
And in the warden gem
the problem occured at the method _run_callbacks(*args)
def _run_callbacks(*args) #:nodoc:
self.class._run_callbacks(*args)
end
Arguments passe to this method are:
[:after_set_user, #<User id: 4, nickname: "max", email: "test@test", birth_at: nil, created_at: "2020-01-12 22:44:19", updated_at: "2020-01-13 21:44:57">, Warden::Proxy:70223361236700 @config={:default_scope=>:user, :scope_defaults=>{}, :default_strategies=>{:user=>[:jwt, :rememberable, :database_authenticatable]}, :intercept_401=>false, :failure_app=>MyappFailureApp}, {:scope=>:user, :recall=>"sessions#new", :store=>true, :event=>:authentication}]
If I change the method to this
def _run_callbacks(*args) #:nodoc:
return
self.class._run_callbacks(*args)
end
It's working well.
I expected to find the solution by myself with digging in the gem and comparing my results with my spec but I honestly don't understand what this methods really do and why it's different with my spec.
Devise
defines multiple hooks on warden
, which are invoked via _run_callbacks
method.
It looks like you have a failure in one of those callback hooks. The hooks can be found here in the Devise source.
Also your MyappFailureApp
isn't really displaying the error, would it be possible to define a nicer one ? Something like -
class MyappFailureApp < Devise::FailureApp
def respond
http_auth
end
def http_auth
self.status = 401
self.headers["WWW-Authenticate"] = %(Bearer realm=#{Devise.http_authentication_realm.inspect}) if http_auth_header?
self.content_type = 'application/json'
self.response_body = http_auth_body
end
def http_auth_body
{ error: [i18n_message] }.to_json
end
def request_format
:json
end
end