Skip to content

Server, Admin: Add passkey authentication - #340

Merged
lehni merged 1 commit into
refactor/remove-passportfrom
feature/passkeys
Oct 17, 2026
Merged

lehni merged 1 commit into
refactor/remove-passportfrom
feature/passkeys

Conversation

@lehni

@lehni lehni commented Oct 16, 2026 •

Copy link
Copy Markdown
Contributor

Builds on #326. Users of any UserMixin model can log in with passkeys (WebAuthn), in Dito.js' admin and in any other frontend through the same endpoints.

Server:

  • CredentialMixin / CredentialModel: one table for the credentials of all user models (passkeys now, later TOTP and backup codes), referring to users by model name and id. Credentials are deleted along with their users.
  • app.auth: { credentials: { modelClass }, passkeys: { name, id, origins } }. Passkeys need sessions stored on the server, so old cookies can't replay challenges, and challenges expire after 5 minutes.
  • UsersController actions, only routed with app.auth.passkeys: post passkey-login-options, post passkey-login, and for the logged-in user get passkeys, post passkey-options, post passkeys, delete passkeys/:id. Controllers with a collection.allow list have to list them.
  • @simplewebauthn/server is an optional peer, imported once in UsersController.setup(), which is now asynchronous. Controller.setup() is internal, like Model.setup().

Admin:

  • login: { passkeys: true } adds a "Sign In with Passkey" button to the login dialog and a Security dialog to the account menu, built from Dito.js schema components: a Password row with a placeholder and a "Change" button, which opens the dialog to change the password (post password, which checks the current password), and a list of the user's passkeys (named after their provider through aaguids, e.g. "1Password", or "Passkey"; created, last used; deletable) with an "Add Passkey" button.
  • New public context.reload(), which reloads the nearest list or object, e.g. after a button's action.
  • New list option empty, a text shown when the list has no items.
  • Objects that render their item as text align it with the text of their buttons.
  • Fix: lists that load their own resource outside a route (e.g. in dialogs) no longer read or change the page's route query.
  • Behaviour change: dialogs validate their data on submit.
  • @simplewebauthn/browser is a required peer, since optional peers break app builds.

Tests: the server tests use a software P-256 authenticator on PGlite and SQLite, covering challenge replay and expiry, other user models, duplicates and deletion. An e2e test uses Chrome's virtual authenticator.

@lehni
lehni added this pull request to stack #341 October 16, 2026 23:05
@lehni lehni changed the title Server, Admin: Add passkeys Server, Admin: Add passkey authentication Oct 16, 2026
@lehni
lehni force-pushed the feature/passkeys branch 2 times, most recently from c497585 to aebc9ec Compare October 17, 2026 01:25
- Add CredentialMixin and CredentialModel, one table for the credentials of all user models, deleted with their users
- Configure credentials and passkeys in app.auth, checked on setup, with sessions stored on the server
- Add passkey login, the user's own passkeys named after their providers, and 'post password' to UsersController, passkeys only routed with them, through the optional peer @simplewebauthn/server
- Add login.passkeys to the admin: a passkey login and a Security dialog in the account menu that changes the password and manages passkeys, with context.reload(), the list option empty, dialogs that validate on submit, and lists in dialogs that keep their query to themselves
- Test with a software authenticator on PGlite and SQLite, and with a virtual authenticator in e2e
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant