Our WebauthnAuthenticationGenerator injects webauthn logic to the user model, and as part of that logic, it generates an after_initialize callback that is used to set the webauthn_id:
|
def inject_webauthn_content_to_user_model |
|
inject_into_file "app/models/user.rb", after: "normalizes :email_address, with: ->(e) { e.strip.downcase }\n" do |
|
<<-RUBY.strip_heredoc.indent(2) |
|
|
|
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 |
|
RUBY |
|
end |
The problem is that this callback sets webauthn_id in memory on every model load, but for existing users who don't yet have a webauthn_id, the generated value is not saved to the database until the user is updated in some way. Until that happens, since no controller in the passkeys/security keys registration flow calls save on the user record, each request generates a different ephemeral value, which makes it so that the credentials are stored in the authenticators with different identifiers for the same user.
Our
WebauthnAuthenticationGeneratorinjects webauthn logic to the user model, and as part of that logic, it generates anafter_initializecallback that is used to set thewebauthn_id:webauthn-rails/lib/generators/webauthn_authentication/webauthn_authentication_generator.rb
Lines 164 to 182 in 1aca187
The problem is that this callback sets
webauthn_idin memory on every model load, but for existing users who don't yet have awebauthn_id, the generated value is not saved to the database until the user is updated in some way. Until that happens, since no controller in the passkeys/security keys registration flow callssaveon the user record, each request generates a different ephemeral value, which makes it so that the credentials are stored in the authenticators with different identifiers for the same user.