Resources

Download Source Code

Summary

# Terminal
bundle add devise_fido_usf
rails g devise_fido_usf:install
rails g devise_fido_usf:views
rails g devise:views
yarn add u2f-api

# 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,
         :fido_usf_registerable, :fido_usf_authenticatable
end

# views/layouts/application.html.erb
<%= javascript_include_tag 'u2f-api.js', 'data-turbolinks-track': 'reload' %>

# config/initializers/assets.rb
Rails.application.config.assets.paths << Rails.root.join('node_modules')
Rails.application.config.assets.precompile += %w( u2f-api.js )

# db/migrate/20210627014642_create_fido_usf_devices.rb
class CreateFidoUsfDevices < ActiveRecord::Migration[6.1]
  def change
    create_table :fido_usf_devices do |t|
      t.references  :user,                  null: false, polymorphic: true, index: true
      t.string      :name,                  null: false, default: ''
      t.string      :key_handle,            null: false, limit: 255, default: ''
      t.binary      :public_key,            null: false, limit: 10.kilobytes
      t.binary      :certificate,           null: false, limit: 1.megabyte
      t.integer     :counter,               null: false, default: 0
      t.timestamp   :last_authenticated_at, null: false
      t.timestamps
    end
    add_index :fido_usf_devices, :key_handle
    add_index :fido_usf_devices, :last_authenticated_at
  end
end

# views/devise/registrations/edit.html.erb
<h2>Hardware Keys</h2>
<% if current_user.fido_usf_devices.empty? %>
  <p>No devices registered</p>
<% else %>
  <%= render 'devise/fido_usf_registrations/devices' %>
  <p class="text-muted">
    Sign in will always require a second
    factor during authentication as active
    as long as at least one FIDO U2F device
    is registered for your account!
    Delete all of aboves FIDO U2F devices
    to disable second factor authentication.
  </p>
<% end %>
<p><%= link_to t('devise.registrations.register_2fa'),
  new_user_fido_usf_registration_path, class: 'btn btn-primary' %></p>

# application_controller.rb
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception, prepend: true
end

# views/devise/fido_usf_registrations/destroy.js.erb
// $('#device_<%= @fade_out_id %>').fadeOut(400, function () {
//   $('#devices').html('<%= j(render(partial: "devise/fido_usf_registrations/device", collection: @devices)) %>')
// } );

elements = document.getElementById('devices')
elements.innerHTML = "<%= j render(partial: 'devise/fido_usf_registrations/device', collection: @devices) %>"