Track Devise login activity
🍊 Battle-tested at Instacart
Add this line to your application’s Gemfile:
gem 'authtrail'And run:
rails generate authtrail:install
rails db:migrateA LoginActivity record is created every time a user tries to login. You can then use this information to detect suspicious behavior. Data includes:
scope- Devise scopestrategy- Devise strategyidentity- email addresssuccess- whether the login succeededfailure_reason- if the login faileduser- the user if the login succeededcontext- controller and actionip- IP addressuser_agentandreferrer- from browsercity,region,country,latitude, andlongitude- from IPcreated_at- time of event
Exclude certain attempts from tracking - useful if you run acceptance tests
AuthTrail.exclude_method = lambda do |info|
info[:identity] == "[email protected]"
endWrite data somewhere other than the login_activities table
AuthTrail.track_method = lambda do |info|
# code
endUse a custom identity method
AuthTrail.identity_method = lambda do |request, opts, user|
if user
user.email
else
request.params.dig(opts[:scope], :email)
end
endAssociate login activity with your user model
class User < ApplicationRecord
has_many :login_activities, as: :user # use :user no matter what your model name
endThe LoginActivity model uses a polymorphic association so it can be associated with different user models.
IP geocoding is performed in a background job so it doesn’t slow down web requests. You can disable it entirely with:
AuthTrail.geocode = falseSet job queue for geocoding
AuthTrail::GeocodeJob.queue_as :lowTo avoid calls to a remote API, download the GeoLite2 City database and configure Geocoder to use it.
Add this line to your application’s Gemfile:
gem 'maxminddb'And create an initializer at config/initializers/geocoder.rb with:
Geocoder.configure(
ip_lookup: :geoip2,
geoip2: {
file: Rails.root.join("lib", "GeoLite2-City.mmdb")
}
)Protect the privacy of your users by encrypting fields that contain personal information, such as identity and ip. Lockbox is great for this. Use Blind Index so you can still query the fields.
class LoginActivity < ApplicationRecord
encrypts :identity, :ip
blind_index :identity, :ip
endWe recommend using this in addition to Devise’s Lockable module and Rack::Attack.
Check out Hardening Devise and Secure Rails for more best practices.
To store latitude and longitude, create a migration with:
add_column :login_activities, :latitude, :float
add_column :login_activities, :longitude, :floatView the changelog
Everyone is encouraged to help improve this project. Here are a few ways you can help:
- Report bugs
- Fix bugs and submit pull requests
- Write, clarify, or fix documentation
- Suggest or add new features