So I dug through Devise's and Warden's code, followed the output from using "caller" at the beginning of my custom failure app, and figured it out.
Devise asks the Lockable strategy if the resource is valid for authentication (via Lockable#valid_for_authentication?). Lockable returns :locked if the resource is locked. Devise stores that result in Warden. To access that result, you just need to check the value of warden.message .
Here's how I did it:
class SessionFailure < Devise::FailureApp
def respond
return super unless request.xhr?
message = I18n.t 'devise.failure.invalid'
cause = 'invalid'
if warden.message == :locked
message = I18n.t 'devise.failure.locked'
cause = 'account_locked'
end
self.status = 200
self.content_type = 'json'
self.response_body = {
:status => 'fail',
:data => { :message => message, :cause => cause },
}.to_json
end
end