Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Passkeys Authentication

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on.

Passkeys Authentication

Passwords are still the default authentication method, despite poor security and UX.

WebAuthn and Passkeys were created by the FIDO Alliance and standardized by W3C to enable secure, passwordless login using public-key cryptography and biometrics.

This talk explains how they work and how to add them to any Ruby app.

Avatar for Braulio Martinez

Braulio Martinez

April 09, 2026

More Decks by Braulio Martinez

Other Decks in Technology

Transcript

  1. WhatsApp’s authentication Factors: ◦ Phone number ownership - Possession ▪

    Proved by typing a code received via SMS ◦ [Optional] 6-digit PIN - Knowledge
  2. Passwords ◦ Prone to phishing, brute force, etc ◦ All

    users compromised if hackers access a DB or a server ◦ Repetition across systems ◦ Bad UX
  3. Most used second factors ◦ One Time Password (OTP) via

    SMS ◦ Time based OTP ▪ Apps (e.g. Google Authenticator) ▪ Physical
  4. 64% of users use some kind of second authentication factor

    as of 2024 https://tinyurl.com/4veap5mr
  5. By 2024, 90% of organizations in the world have suffered

    phishing attacks. The avg cost per breach of 4.88M https://zensec.co.uk/blog/2025-phishing-statistics-the-alarming-rise-in -attacks/
  6. WebAuthn (Web Authentication) is a standard that defines a set

    of rules for APIs to enable users to strongly register and authenticate on applications using public key based cryptography.
  7. +

  8. The Entities ◦ Authenticator => User Device ▪ Creating and

    holding credentials securely, signing ◦ Client => Web Browser (or Native APIs for mobile) ◦ Relying Party => Web App
  9. The User Flows ◦ Attestation => Registration (of a credential)

    ◦ Assertion => Authentication (of a credential)
  10. # app/views/registrations/new.html.erb <%= form_with url: registration_path, ... do |form| %>

    <%= form.text_field :username %> <%= form.text_field :nickname %> <%= form.submit ‘Sign Up’ %> <% end %>
  11. # app/controllers/credentials_controller.rb def create user = User.new(...) options = WebAuthn::Credential.options_for_create(...)

    if user.valid? session[:current_registration] = { challenge: options.challenge, ... } respond_to do |format| format.json { render json: options } end end end
  12. # app/views/sessions/new.html.erb <%= form_with url: session_path, ... do |form| %>

    <%= form.text_field :username %> <%= form.submit ‘Sign In’ %> <% end %>
  13. # app/controllers/sessions_controller.rb def create user = User.find_by(...) if user options

    = WebAuthn::Credential.options_for_get( allow: user.credentials.pluck(:external_id), ... ) session[:current_authentication] = { challenge: options.challenge, ... } respond_to do |format| format.json { render json: options } end end end
  14. # app/javascript/credentials.js navigator.credentials.get({ publicKey: { allowedCredentials: [{ id: registeredCredId, …

    }] } }).then(function(credential) { authenticateCredentialWithServer(credential); });
  15. # app/javascript/credentials.js navigator.credentials.get({ publicKey: { allowedCredentials: [{ id: registeredCredId, …

    }] } }).then(function(credential) { authenticateCredentialWithServer(credential); });
  16. # app/controllers/credentials_controller.rb def authenticate credential = WebAuthn::Credential.from_get(params[:credential]) registered_credential = current_user

    .webauthn_credentials .find_by(webauthn_id: credential.id) credential.verify(…, public_key: registered_credential.public_key) # return success end
  17. WebAuthn as a 2nd & 3rd Factor 1st: Password -

    Knowledge 2nd: WebAuthn Credential - Possession 3rd: WebAuthn User Verification - Knowledge or Inherence
  18. WebAuthn as a 2nd & 3rd Factor 1st: Password -

    Knowledge 2nd: WebAuthn Credential - Possession 3rd: WebAuthn User Verification - Knowledge or Inherence
  19. WebAuthn as 1st & 2nd factor 1st: WebAuthn Credential -

    Possession 2nd: WebAuthn User Verification - Knowledge or Inherence
  20. Can AI Agents fake the “User Gesture” ? • User

    Presence - No • Optionally: User Verification - No
  21. Passkeys Newest Features (Part 1) • Conditional/Autofill UI (Conditional Mediation)

    - Get site creds in authenticator • Credential Backup State Flags (BE/BS) - E.g enforce other factor • Cross Device Authentication - Roaming authenticators • Client Capabilities API - getClientCapabilities()
  22. Passkeys Newest Features (Part 2) • Credential conditional creation -

    prompts user to create passkey on non-passkey flows • Related Origin Requests (ROR) (cedarcode.com, cedarcode.net ) - Through RP exposing .well-known/webauthn • Signals API - Remove unused credentials, among others • AAGUID - Authenticator metadata to allow device ID
  23. Are multi device (synced) Passkeys as secure as device bound

    Passkeys? https://thehackernews.com/2025/10/how-attackers-bypass-synced-passkeys.html
  24. # app/models/user.rb class User < ApplicationRecord devise :database_authenticatable, . .

    . :passkey_authenticatable, :webauthn_two_factor_authenticatable end # config/initializers/webauthn.rb - Generated by install generator WebAuthn.configure do |config| config.allowed_origins = ["https://yourapp.com"] config.rp_name = "Your App Name" end
  25. <%= login_with_passkey_form_for(:user) do |form| %> <%= form.submit "Log in with

    passkeys" %> <% end %> <%= login_with_security_key_form_for(@resource) do |form| %> <%= form.submit "Use security key" %> <% end %> <%= passkey_creation_form_for(:user) do |form| %> <%= form.label :name, 'Passkey name' %> <%= form.text_field :name, required: true %> <%= form.submit 'Create Passkey' %> <% end %> Passkey Authentication 1st & only Factor Passkey Authentication 2st Factor Passkey Registration
  26. ◦ webauthn-ruby v3.4.3 ▪ Maintenance and staying on edge on

    dependencies ▪ Evolving as well as the standard keeps changing ◦ passkeys + Digital Credentials ◦ passkeys for checkouts (SPC)