Resources

HaveIBeenPwned - https://haveibeenpwned.com/
devise-pwned_password gem - https://github.com/michaelbanfield/devise-pwned_password
This episode is sponsored by Honeybadger

Download Source Code

Summary

# Terminal
rails g devise:views
bundle add devise-pwned_password

# Devise Template
gem 'devise'
run 'bundle install'
generate('devise:install')
generate(:devise, 'User')

environment 'config.action_mailer.default_url_options = { host: "localhost", port: 3000 }', env: 'development'
environment 'config.action_mailer.default_url_options = { host: "https://example.com" }', env: 'production'

append_to_file 'app/views/layouts/_navigation_links.html.erb' do
  <<~'HEREDOC'

  <% if user_signed_in? %>
    <li class="nav-item me-4">
      <%= link_to "Sign Out", destroy_user_session_path, "data-turbo-method": :delete, class: "nav-link" %>
    </li>
  <% else %>
    <li class="nav-item me-4">
      <%= link_to "Sign In", new_user_session_path, class: 'nav-link' %>
    </li>
  <% end %>
  HEREDOC
end

rake 'db:migrate'

git add: '.'
git commit: %( -m 'added devise')

# In Devise form views
html: { "data-turbo": false }

# models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable
  devise :pwned_password unless Rails.env.test?
end

# views/layouts/_navigation_links.html.erb
<% if user_signed_in? %>
  <li class="nav-item me-4">
    <%= link_to "My Account", edit_user_registration_path, class: "nav-link" %>
  </li>
  <li class="nav-item me-4">
    <%= link_to "Sign Out", destroy_user_session_path, "data-turbo-method": :delete, class: "nav-link" %>
  </li>
<% else %>
  <li class="nav-item me-4">
    <%= link_to "Sign In", new_user_session_path, class: 'nav-link' %>
  </li>
<% end %>

# config/locales/devise.en.yml
en:
  devise:
    sessions:
      warn_pwned: "Your password has been leaked. Please change your password."
  errors:
    messages:
      pwned_password: "has previously appeared in a data breach. Choose something different! ❤️"

# config/initializers/devise.rb
Devise.setup do |config|
  config.min_password_matches = 5
  config.min_password_matches_warn = 5
  ...
end

# application_controller.rb
class ApplicationController < ActionController::Base
  def after_sign_in_path_for(resource)
    set_flash_message! :alert, :warn_pwned if resource.respond_to?(:pwned?) && resource.pwned?
    super
  end
end