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. attr_encrypted is great for this. Use blind_index so you can still query the fields.
class LoginActivity < ApplicationRecord
attr_encrypted :identity, key: ...
attr_encrypted :ip, key: ...
blind_index :identity, key: ...
blind_index :ip, key: ...
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.
Works with Rails 4.2+
To store latitude and longitude, create a migration with:
add_column :login_activities, :latitude, :decimal, precision: 10, scale: 8
add_column :login_activities, :longitude, :decimal, precision: 11, scale: 8View 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