Skip to content

Commit ea83da3

Browse files
RenzoMinelliclaude
andcommitted
fix: scope form helpers to the Devise resource
The form helpers (login_with_passkey_form_for, etc.) used form_with without a scope, so form builder fields like f.check_box :remember_me generated name="remember_me" instead of name="account[remember_me]". Since the passkey strategy reads params[scope][:remember_me], the value was never found. Resolve the scope via Devise::Mapping.find_scope! and pass it to form_with. Switch the internal public_key_credential hidden field to hidden_field_tag so it stays at the top-level params where strategies and controllers expect it. Update controllers to read :name from the now-scoped params. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent fe11674 commit ea83da3

7 files changed

Lines changed: 26 additions & 18 deletions

File tree

app/controllers/devise/passkeys_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ def verify_and_save_passkey(passkey_from_params)
4747

4848
resource.passkeys.create(
4949
external_id: passkey_from_params.id,
50-
name: params[:name],
50+
name: params.dig(resource_name, :name),
5151
public_key: passkey_from_params.public_key,
5252
sign_count: passkey_from_params.sign_count
5353
)

app/controllers/devise/second_factor_webauthn_credentials_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def verify_and_save_security_key(security_key_from_params)
5656

5757
resource.second_factor_webauthn_credentials.create(
5858
external_id: security_key_from_params.id,
59-
name: params[:name],
59+
name: params.dig(resource_name, :name),
6060
public_key: security_key_from_params.public_key,
6161
sign_count: security_key_from_params.sign_count
6262
)

lib/devise/webauthn/helpers/credentials_helper.rb

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,56 @@ module Devise
44
module Webauthn
55
module CredentialsHelper
66
def passkey_creation_form_for(resource_or_resource_name, **options, &block)
7+
scope = Devise::Mapping.find_scope!(resource_or_resource_name)
8+
79
form_with(
8-
**options, url: passkeys_path(resource_or_resource_name), method: :post
10+
**options, scope: scope, url: passkeys_path(resource_or_resource_name), method: :post
911
) do |f|
1012
tag.webauthn_create(data: { options_url: passkey_registration_options_path(resource_or_resource_name) }) do
11-
concat f.hidden_field(:public_key_credential, data: { webauthn_target: "response" })
13+
concat hidden_field_tag(:public_key_credential, nil, data: { webauthn_target: "response" })
1214
concat capture(f, &block)
1315
end
1416
end
1517
end
1618

1719
def login_with_passkey_form_for(resource_or_resource_name, **options, &block)
20+
scope = Devise::Mapping.find_scope!(resource_or_resource_name)
21+
1822
form_with(
19-
**options, url: session_path(resource_or_resource_name), method: :post
23+
**options, scope: scope, url: session_path(resource_or_resource_name), method: :post
2024
) do |f|
2125
tag.webauthn_get(data: { options_url: passkey_authentication_options_path(resource_or_resource_name) }) do
22-
concat f.hidden_field(:public_key_credential, data: { webauthn_target: "response" })
26+
concat hidden_field_tag(:public_key_credential, nil, data: { webauthn_target: "response" })
2327
concat capture(f, &block)
2428
end
2529
end
2630
end
2731

2832
def security_key_creation_form_for(resource_or_resource_name, **options, &block)
33+
scope = Devise::Mapping.find_scope!(resource_or_resource_name)
34+
2935
form_with(
30-
**options, url: second_factor_webauthn_credentials_path(resource_or_resource_name), method: :post
36+
**options, scope: scope, url: second_factor_webauthn_credentials_path(resource_or_resource_name), method: :post
3137
) do |f|
3238
tag.webauthn_create(
3339
data: { options_url: security_key_registration_options_path(resource_or_resource_name) }
3440
) do
35-
concat f.hidden_field(:public_key_credential, data: { webauthn_target: "response" })
41+
concat hidden_field_tag(:public_key_credential, nil, data: { webauthn_target: "response" })
3642
concat capture(f, &block)
3743
end
3844
end
3945
end
4046

4147
def login_with_security_key_form_for(resource_or_resource_name, **options, &block)
48+
scope = Devise::Mapping.find_scope!(resource_or_resource_name)
49+
4250
form_with(
43-
**options, url: two_factor_authentication_path(resource_or_resource_name), method: :post
51+
**options, scope: scope, url: two_factor_authentication_path(resource_or_resource_name), method: :post
4452
) do |f|
4553
tag.webauthn_get(data: {
4654
options_url: security_key_authentication_options_path(resource_or_resource_name)
4755
}) do
48-
concat f.hidden_field(:public_key_credential, data: { webauthn_target: "response" })
56+
concat hidden_field_tag(:public_key_credential, nil, data: { webauthn_target: "response" })
4957
concat capture(f, &block)
5058
end
5159
end

spec/helpers/devise/webauthn/credentials_helper_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,8 @@ def have_hidden_credential_field
101101
page = parse(html)
102102

103103
expect(page).to have_css("input.btn-primary[type='submit']")
104-
expect(page).to have_css("input[type='checkbox'][name='remember_me']")
105-
expect(page).to have_css("label[for='remember_me']", text: "Remember me")
104+
expect(page).to have_css("input[type='checkbox'][name='account[remember_me]']")
105+
expect(page).to have_css("label[for='account_remember_me']", text: "Remember me")
106106
end
107107
end
108108

spec/internal/app/views/devise/sessions/new.html.erb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@
2525

2626
<%= login_with_passkey_form_for(resource_name, id: "passkey-login") do |form| %>
2727
<div class="field">
28-
<%= check_box_tag "account[remember_me]", id: "passkey_remember_me" %>
29-
<%= label_tag "passkey_remember_me", "Remember me" %>
28+
<%= form.check_box :remember_me %>
29+
<%= form.label :remember_me %>
3030
</div>
3131

3232
<%= form.submit "Log in with passkeys" %>

spec/requests/devise/passkeys_controller_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646
assert_difference("user.passkeys.count", 1) do
4747
post account_passkeys_path, params: {
4848
public_key_credential: credential.to_json,
49-
name: "My Passkey"
49+
account: { name: "My Passkey" }
5050
}
5151
end
5252

@@ -68,7 +68,7 @@
6868
assert_difference("user.passkeys.count", 0) do
6969
post account_passkeys_path, params: {
7070
public_key_credential: invalid_credential.to_json,
71-
name: "My Passkey"
71+
account: { name: "My Passkey" }
7272
}
7373
end
7474

spec/requests/devise/second_factor_webauthn_credentials_controller_spec.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@
5656
assert_difference("user.second_factor_webauthn_credentials.count", 1) do
5757
post account_second_factor_webauthn_credentials_path, params: {
5858
public_key_credential: credential.to_json,
59-
name: "My Security Key"
59+
account: { name: "My Security Key" }
6060
}
6161
end
6262

@@ -78,7 +78,7 @@
7878
assert_difference("user.second_factor_webauthn_credentials.count", 0) do
7979
post account_second_factor_webauthn_credentials_path, params: {
8080
public_key_credential: invalid_credential.to_json,
81-
name: "My Security Key"
81+
account: { name: "My Security Key" }
8282
}
8383
end
8484

0 commit comments

Comments
 (0)