I had the same question but was unable to resolve it using the "warden.options"
since, in my case, these were being cleared before redirecting to the sessions#new
action. After looking into a few alternatives that I judged to be too brittle (because they involved extending some Devise classes and aliasing existing methods), I wound up using some callbacks provided by Warden
. It works better for me because the callback is invoked inside the current request-response cycle and the parameters are all preserved in the env
object.
These callbacks are named and appear to be designed to solve this and related problems. And they are documented!
Warden supports the following callbacks as of warden-1.2.3
:
after_set_user
after_authentication
(useful for logging successful sign ins)
after_fetch
(alias for after_set_user
)
before_failure
(useful for logging failed sign ins - example below)
after_failed_fetch
before_logout
on_request
Each callback is set directly on the Warden::Manager
class (may be inside config/initializers/devise.rb). To track a failed authentication attempt I added this:
Warden::Manager.before_failure do |env, opts|
email = env["action_dispatch.request.request_parameters"][:user] &&
env["action_dispatch.request.request_parameters"][:user][:email]
# unfortunately, the User object has been lost by the time
# we get here; so we take a db hit because I care to see
# if the email matched a user account in our system
user_exists = User.where(email: email).exists?
if opts[:message] == :unconfirmed
# this is a special case for me because I'm using :confirmable
# the login was correct, but the user hasn't confirmed their
# email address yet
::Rails.logger.info "*** Login Failure: unconfirmed account access: #{email}"
elsif opts[:action] == "unauthenticated"
# "unauthenticated" indicates a login failure
if !user_exists
# bad email:
# no user found by this email address
::Rails.logger.info "*** Login Failure: bad email address given: #{email}"
else
# the user exists in the db, must have been a bad password
::Rails.logger.info "*** Login Failure: email-password mismatch: #{email}"
end
end
end
I expect that you could use the before_logout
callback to track logout actions as well, but I haven't tested it. There appear to be prepend_
variants of the callbacks as well.