# 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) %>"