WebAuthn Rails
webauthn-rails adds passkeys to your Rails app with almost no setup. It provides a generator that installs everything you need for a secure passwordless and two-factor authentication flow, built on top of the Rails Authentication system. Webauthn Rails combines Stimulus for the frontend experience with the WebAuthn Ruby gem on the server side – giving you a ready-to-use authentication system.
Requirements
- Ruby: 3.2+
- Rails: 8.0+
- Stimulus Rails: This gem requires stimulus-rails to be installed and configured in your application
JavaScript Dependencies
The generator automatically handles JavaScript dependencies based on your setup:
-
Importmap: Pins
@github/webauthn-json/browser-ponyfill
to your importmap - Node.js/Yarn/Bun: Adds the package to your package manager
Usage
Install the gem by running:
$ bundle add webauthn-rails --group development
Next, you need to run the generator:
$ bin/rails generate webauthn_authentication
If you haven't generated Rails authentication yet, you can pass the --with-rails-authentication
flag in order to generate it alongside the webauthn authentication:
$ bin/rails generate webauthn_authentication --with-rails-authentication
This generator will:
-
Optionally invoke the Rails Authentication generator if the
--with-rails-authentication
flag is passed. - Modifies the
SessionsController
to support WebAuthn two-factor authentication. - Create controllers for handling passwordless and two-factor authentication, as well as credential management.
- Update new session views to support passkey authentication.
- Add views for credential management and two-factor authentication.
- Update the
User
model to include association with credentials and webauthn-related logic. - Generate database migrations for WebAuthn credentials.
- Add passkey authentication, two-factor authentication and credential management routes.
- Generate a Stimulus controller for WebAuthn interactions.
- Create the WebAuthn initializer.
Post-Installation Configuration
After running the generator, you must configure the WebAuthn settings:
- Edit
config/initializers/webauthn.rb
and set your allowed origins and Relying Party name:
WebAuthn.configure do |config|
# This value needs to match `window.location.origin` evaluated by
# the User Agent during registration and authentication ceremonies.
config.allowed_origins = ["https://yourapp.com"]
# Relying Party name for display purposes
config.rp_name = "Your App Name"
end
- Run the migrations:
$ bin/rails db:migrate
How it Works
User Sign-In
Users can sign in by visiting /session/new
. The generated setup supports two ways to log in:
- Email and password – via the standard Rails Authentication flow. On top of that, if the user has enabled two-factor authentication, they will be prompted to verify with a WebAuthn credential.
- Passkey (WebAuthn) – by selecting a passkey linked to the user’s account.
The WebAuthn passkey sign-in flow works as follows:
- User clicks "Sign in with Passkey", starting a WebAuthn authentication ceremony.
- Browser shows available passkeys.
- User selects a passkey and verifies with their authenticator.
- The server verifies the response and signs in the user.
The WebAuthn two-factor authentication flow works as follows:
- User signs in with email and password.
- If the user has 2FA enabled, they are asked to use a webauthn credential to complete sign-in.
- User selects a credential and verifies with their authenticator.
- The server verifies the response and completes sign-in.
Adding Credentials
Signed-in users can add passkeys by visiting /passkeys/new
, and second factor credentials by visiting /second_factor_webauthn_credentials/new
.
Models
User Model
The generator adds WebAuthn functionality to your User model:
class User < ApplicationRecord
has_many :webauthn_credentials, dependent: :destroy
with_options class_name: "WebauthnCredential" do
has_many :second_factor_webauthn_credentials, -> { second_factor }
has_many :passkeys, -> { passkey }
end
after_initialize do
self.webauthn_id ||= WebAuthn.generate_user_id
end
def second_factor_enabled?
webauthn_credentials.any?
end
end
WebauthnCredential Model
Stores the public keys and metadata for each registered authenticator:
class WebauthnCredential < ApplicationRecord
belongs_to :user
validates :external_id, :public_key, :nickname, :sign_count, presence: true
validates :external_id, uniqueness: true
validates :sign_count,
numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 2**32 - 1 }
enum :authentication_factor, { first_factor: 0, second_factor: 1 }
scope :passkey, -> { first_factor }
end
Customization
Views
The generator creates view templates that you can customize:
-
app/views/passkeys/new.html.erb
- Add new passkey form. -
app/views/second_factor_webauthn_credentials/new.html.erb
- Add new second factor credential form. -
app/views/second_factor_authentications/new.html.erb
- Two-factor authentication form.
Stimulus Controller
The generated Stimulus controller (webauthn_credentials_controller.js
) handles the WebAuthn JavaScript API interactions. You can extend or customize it for your specific needs.
Contributing
Issues and pull requests are welcome on GitHub at https://github.com/cedarcode/webauthn-rails.
Development
After checking out the repo, run:
$ bundle install
To run the tests:
$ bundle exec rake test
$ bundle exec rake test_dummy
To run the linter:
$ bundle exec rubocop
Before submitting a PR, make sure both tests pass and there are no linting errors.
License
The gem is available as open source under the terms of the MIT License.