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.
- Ruby: 3.2+
- Rails: 8.0+
- Stimulus Rails: This gem requires stimulus-rails to be installed and configured in your application for the generated code to work out of the box.
Note: If you prefer not to have the stimulus-rails dependency, you’ll need to manually implement the JavaScript logic for WebAuthn interactions.
The generator automatically handles JavaScript dependencies based on your setup:
- Importmap: Pins
@github/webauthn-json/browser-ponyfillto your importmap - Node.js/Yarn/Bun: Adds the package to your package manager
Install the gem by running:
$ bundle add webauthn-rails --group developmentNext, you need to run the generator:
$ bin/rails generate webauthn_authenticationIf 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-authenticationThis generator will:
- Optionally invoke the Rails Authentication generator if the
--with-rails-authenticationflag is passed. - Modifies the
SessionsControllerto 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
Usermodel 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.
After running the generator, you must configure the WebAuthn settings:
- Edit
config/initializers/webauthn.rband 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:migrateUsers 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.
Signed-in users can add passkeys by visiting /passkeys/new, and second factor credentials by visiting /second_factor_webauthn_credentials/new.
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
endStores 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 }
endThe 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.
The generated Stimulus controller (webauthn_credentials_controller.js) handles the WebAuthn JavaScript API interactions. You can extend or customize it for your specific needs.
Issues and pull requests are welcome on GitHub at https://github.com/cedarcode/webauthn-rails.
After checking out the repo, run:
$ bundle installTo run the tests:
$ bundle exec rake test
$ bundle exec rake test_dummyTo run the linter:
$ bundle exec rubocopBefore submitting a PR, make sure both tests pass and there are no linting errors.
The gem is available as open source under the terms of the MIT License.