Polish up Passkey interface

- Fix indentation
- Split awkward initializer into separate methods
- Rename credentials to passkeys
- Simplify authenticator registry loading
- Flatten nested errors under ActionPack::WebAuthn
- Set passkey current params only requests that use it
- Inline anemic methods
- Replace custom validation with ActiveModel::Validation
- Rename identity to holder in Passkey
- Rename credentials to passkeys in JS
- Extract framework library out of controllers
- Pass params hashes down to ActionPack
- Attempt to simplify public interface
- Push data decoding down to the classes representing the data
- Introduce has_passkeys
- Add CBOR bigint support
- Rename ActionPack::WebAuthn::Passkey to ActionPack::Passkey
- Add create_passkey_button helper
- Rename public-key to creation-options
- Add sign_in_with_passkey_button helper
- Dispatch events for the whole Passkey lifecycle
- Add ED25519 support
- Prevent crash on missing meta tag
- Validate resident key options
- Don't clobber existing ActionPack config options
- Validate cryptographic params
- Move CurrentWebAuthnRequest into ActionPack::Passkey
- Use ActiveModel::Attributes for Options objects
- Implement expiring challanges
- Add lifecycle events
- Extract param helpers into Request
- Add passkey_creation_options and passkey_request_options helpers
- Add create_passkey_challenge to make it easier to override the create method if needed
- Prefix all view helpers with passkey_
- Auto-include ActionPack::Passkey::Holder
- Make the passkey challange url configurable
- Add a reminder about Passkeys to the magic link email
This commit is contained in:
Stanko K.R.
2026-03-04 14:12:40 +01:00
parent f4fbe17b22
commit 017bcc9ce1
73 changed files with 2326 additions and 1103 deletions
@@ -0,0 +1,20 @@
class CreateActionPackPasskeys < ActiveRecord::Migration[8.2]
def change
create_table :action_pack_passkeys, id: :uuid do |t|
t.uuid :holder_id, null: false
t.string :holder_type, null: false
t.string :credential_id, null: false
t.binary :public_key, null: false
t.integer :sign_count, null: false, default: 0
t.string :name
t.text :transports
t.string :aaguid
t.boolean :backed_up
t.timestamps
t.index [ :holder_type, :holder_id ]
t.index :credential_id, unique: true
end
end
end
@@ -1,17 +0,0 @@
class CreateIdentityCredentials < ActiveRecord::Migration[8.2]
def change
create_table :identity_credentials, id: :uuid do |t|
t.uuid :identity_id, null: false
t.string :credential_id, null: false
t.binary :public_key, null: false
t.integer :sign_count, null: false, default: 0
t.string :name
t.text :transports
t.timestamps
t.index :identity_id
t.index :credential_id, unique: true
end
end
end
@@ -1,6 +0,0 @@
class AddAaguidAndBackedUpToIdentityCredentials < ActiveRecord::Migration[8.2]
def change
add_column :identity_credentials, :aaguid, :string
add_column :identity_credentials, :backed_up, :boolean
end
end
Generated
+17 -16
View File
@@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[8.2].define(version: 2026_02_19_095815) do
ActiveRecord::Schema[8.2].define(version: 2026_02_18_120000) do
create_table "accesses", id: :uuid, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.datetime "accessed_at"
t.uuid "account_id", null: false
@@ -69,6 +69,22 @@ ActiveRecord::Schema[8.2].define(version: 2026_02_19_095815) do
t.index ["external_account_id"], name: "index_accounts_on_external_account_id", unique: true
end
create_table "action_pack_passkeys", id: :uuid, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "aaguid"
t.boolean "backed_up"
t.datetime "created_at", null: false
t.string "credential_id", null: false
t.uuid "holder_id", null: false
t.string "holder_type", null: false
t.string "name"
t.binary "public_key", null: false
t.integer "sign_count", default: 0, null: false
t.text "transports"
t.datetime "updated_at", null: false
t.index ["credential_id"], name: "index_action_pack_passkeys_on_credential_id", unique: true
t.index ["holder_type", "holder_id"], name: "index_action_pack_passkeys_on_holder_type_and_holder_id"
end
create_table "action_text_rich_texts", id: :uuid, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.uuid "account_id", null: false
t.text "body", size: :long
@@ -344,21 +360,6 @@ ActiveRecord::Schema[8.2].define(version: 2026_02_19_095815) do
t.index ["identity_id"], name: "index_access_token_on_identity_id"
end
create_table "identity_credentials", id: :uuid, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "aaguid"
t.boolean "backed_up"
t.datetime "created_at", null: false
t.string "credential_id", null: false
t.uuid "identity_id", null: false
t.string "name"
t.binary "public_key", null: false
t.integer "sign_count", default: 0, null: false
t.text "transports"
t.datetime "updated_at", null: false
t.index ["credential_id"], name: "index_identity_credentials_on_credential_id", unique: true
t.index ["identity_id"], name: "index_identity_credentials_on_identity_id"
end
create_table "magic_links", id: :uuid, charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
t.string "code", null: false
t.datetime "created_at", null: false
+16
View File
@@ -69,6 +69,22 @@ ActiveRecord::Schema[8.2].define(version: 2026_02_18_120000) do
t.index ["external_account_id"], name: "index_accounts_on_external_account_id", unique: true
end
create_table "action_pack_passkeys", id: :uuid, force: :cascade do |t|
t.string "aaguid", limit: 255
t.boolean "backed_up"
t.datetime "created_at", null: false
t.string "credential_id", limit: 255, null: false
t.uuid "holder_id", null: false
t.string "holder_type", limit: 255, null: false
t.string "name", limit: 255
t.binary "public_key", null: false
t.integer "sign_count", default: 0, null: false
t.text "transports", limit: 65535
t.datetime "updated_at", null: false
t.index ["credential_id"], name: "index_action_pack_passkeys_on_credential_id", unique: true
t.index ["holder_type", "holder_id"], name: "index_action_pack_passkeys_on_holder_type_and_holder_id"
end
create_table "action_text_rich_texts", id: :uuid, force: :cascade do |t|
t.uuid "account_id", null: false
t.text "body", limit: 4294967295