Skip to content

馃攽 feat: Passkey Authentication with WebAuthn Sign-In and Management - #14715

Draft
berry-13 wants to merge 9 commits into
devfrom
feat/passkey-auth-ui
Draft

馃攽 feat: Passkey Authentication with WebAuthn Sign-In and Management#14715
berry-13 wants to merge 9 commits into
devfrom
feat/passkey-auth-ui

Conversation

@berry-13

@berry-13 berry-13 commented Aug 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds passkey authentication to LibreChat: WebAuthn sign-in from the login page and passkey management from account settings. The feature is opt-in behind ALLOW_PASSKEY_LOGIN and off by default, so existing deployments are unaffected unless they enable it.

Sign-in uses discoverable credentials, so no username is required. Users manage their credentials from a Passkeys panel under Settings > Account, where they can add, rename and remove them. Server-side the ceremonies are backed by @simplewebauthn, with a new passkeys collection that cascades on account deletion.

Account protections included in this PR:

  • Adding or removing a passkey requires confirming the account password, rate limited per user in its own namespace.
  • Enrollment and sign-in are restricted to local-provider accounts, enforced server-side rather than only in the settings UI.
  • The sign-in ceremony requires user verification, so a credential cannot act as a sole factor on possession alone.
  • Account status is re-evaluated once the credential owner is resolved, rather than only before the request is authenticated.
  • Redirect target validation and ceremony failure logging were tightened.

One change reaches beyond the feature and is worth calling out: a password reset now invalidates outstanding access tokens, not just sessions. Previously a reset cleared the session records while already-issued JWTs stayed valid until they expired, because the strategies verified only the signature and expiry. A credentialsChangedAt marker on the user is now compared against the token's issue time in both JWT strategies. This is a behaviour change for existing deployments: after a password reset, a second signed-in device is signed out immediately rather than continuing until its token lapses.

Dependencies: adds @simplewebauthn/server and @simplewebauthn/browser.

Change Type

  • New feature (non-breaking change which adds functionality)
  • This change requires a documentation update

Testing

Unit coverage was added across the passkey controller, the WebAuthn ceremony helpers, the data layer, the step-up limiter, both JWT strategies, the redirect utility and the passkey settings UI.

To reproduce the manual pass, set ALLOW_PASSKEY_LOGIN=true, run a build (required, since packages/data-schemas gains a field), then start the backend and frontend.

Exercised against a running instance:

  1. POST /api/auth/passkey/register/options with no password and with an incorrect password, both rejected with 403, each producing a warning in the server log. The same call with the correct password returns registration options.
  2. Access-token invalidation: the same bearer token returns 200 on /api/user, then 401 once a credential change is recorded, while a freshly issued token continues to work.
  3. Redirect handling from the login page, confirming an attacker-supplied redirect_to cannot move the post-login destination off-origin, and that ordinary in-app redirect targets are still honoured.
  4. The Passkeys settings dialog in light and dark themes, including the password confirmation error state, which sets aria-invalid, points aria-describedby at a role="alert" message and returns focus to the field.

Not covered: the WebAuthn ceremonies themselves have not been driven end to end in a browser, which needs a virtual authenticator. This is the main reason the PR is a draft.

Test Configuration:

  • Node.js 24, MongoDB, Redis enabled
  • ALLOW_PASSKEY_LOGIN=true, ALLOW_EMAIL_LOGIN=true, ALLOW_PASSWORD_RESET=true
  • Relying party derived from DOMAIN_CLIENT

New configuration introduced by this PR:

Variable Default Purpose
ALLOW_PASSKEY_LOGIN unset (off) Enables the feature
PASSKEY_RP_ID / PASSKEY_RP_NAME / PASSKEY_ORIGINS derived from DOMAIN_CLIENT and DOMAIN_SERVER Relying party identity and allowed origins
PASSKEY_MAX / PASSKEY_WINDOW 20 / 5 min Sign-in ceremony throttle, per IP
PASSKEY_STEPUP_MAX / PASSKEY_STEPUP_WINDOW 20 / 15 min Password confirmation throttle, per user

Checklist

  • My code adheres to this project's style guidelines
  • I have performed a self-review of my own code
  • I have commented in any complex areas of my code
  • I have made pertinent documentation changes
  • My changes do not introduce new warnings
  • I have written tests demonstrating that my changes are effective or that my feature works
  • Local unit tests pass with my changes
  • A pull request for updating the documentation has been submitted.

Copilot AI lite review requested due to automatic review settings August 8, 2026 23:22

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@berry-13 berry-13 changed the title feat: passkey authentication (WebAuthn) 馃攽 feat: Passkey Authentication with WebAuthn Sign-In and Management Aug 8, 2026
@berry-13

berry-13 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

馃挕 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7ba7cac620

鈩癸笍 About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 馃憤.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread api/server/controllers/auth/PasskeyController.js
Comment thread api/server/routes/auth.js
Comment thread api/server/controllers/auth/PasskeyController.js
Comment thread client/src/hooks/Auth/usePasskey.ts
Comment thread api/server/services/AuthService.js
Comment thread api/server/controllers/AuthController.js
Comment thread packages/api/src/auth/passkey.ts
Comment thread api/server/controllers/auth/PasskeyController.js
Comment thread client/src/hooks/Auth/usePasskey.ts
@berry-13
berry-13 force-pushed the feat/passkey-auth-ui branch from 7ba7cac to 03b971b Compare August 9, 2026 02:15
@berry-13

berry-13 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

馃挕 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 03b971bfec

鈩癸笍 About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 馃憤.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread api/server/controllers/auth/PasskeyController.js
Comment thread client/src/hooks/Auth/usePasskey.ts
Comment thread client/src/hooks/Auth/usePasskey.ts Outdated
@berry-13
berry-13 force-pushed the feat/passkey-auth-ui branch from 03b971b to b293f9f Compare August 9, 2026 02:56
@berry-13

berry-13 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

馃挕 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b293f9f351

鈩癸笍 About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 馃憤.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/components/Nav/Settings/registry.tsx Outdated
Comment thread api/server/controllers/UserController.js
Comment thread packages/data-schemas/src/methods/passkey.ts Outdated
Comment thread api/cache/getLogStores.js
@berry-13

berry-13 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@berry-13
berry-13 force-pushed the feat/passkey-auth-ui branch from 8e28329 to 7bc957e Compare August 9, 2026 03:25
@berry-13

berry-13 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

馃挕 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7bc957e8d5

鈩癸笍 About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 馃憤.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/components/Nav/SettingsTabs/Account/Passkeys/Passkeys.tsx Outdated
Comment thread api/server/routes/auth.js
@berry-13

berry-13 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

馃挕 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f46be33b73

鈩癸笍 About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 馃憤.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/data-schemas/src/methods/passkey.ts Outdated
@berry-13

berry-13 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

馃挕 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 24f8e8932a

鈩癸笍 About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 馃憤.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread client/src/components/Nav/SettingsTabs/Account/Passkeys/Passkeys.tsx Outdated
Comment thread client/src/hooks/Auth/usePasskey.ts Outdated
Comment thread api/server/controllers/AuthController.js
@berry-13

berry-13 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

馃挕 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5933321976

鈩癸笍 About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 馃憤.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread api/server/controllers/auth/PasskeyController.js
@berry-13

berry-13 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

馃挕 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e00d097cd3

鈩癸笍 About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 馃憤.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread api/server/controllers/auth/PasskeyController.js Outdated
@berry-13

berry-13 commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator Author

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. Breezy!

Reviewed commit: e23917a52f

鈩癸笍 About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 馃憤.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Require password confirmation before adding or removing a passkey, and rate
limit those confirmations per user in their own namespace. Restrict passkey
enrollment and sign-in to local accounts, and re-evaluate account status once
the credential owner is resolved. Require user verification on the sign-in
ceremony. Invalidate outstanding access tokens on password reset. Tighten
redirect target validation and sanitize ceremony failure logs.

Adds coverage across the passkey controller, the WebAuthn helpers, the step-up
limiter, both JWT strategies, the redirect utility and the passkey settings UI.
Send a localized default credential label at enrollment so non-English
locales no longer persist the server's English fallback, and route the
passkey post-login and 2FA navigations through the deployment base path
so subdirectory installs stay inside the router.

Also mock syncStaticTools in the server boot specs; without it the
post-listen MCP initialization calls undefined and exits the worker.
Make the signature counter write a compare-and-swap so two assertions
that verified against the same stored counter cannot both commit, and
reject the losing one; a cloned authenticator is otherwise accepted
inside that window. Counterless authenticators keep restamping at 0.

Keep the passkey panel reachable for identity-provider accounts, which
already get passwordless removal server-side but had no way in, while
hiding the add control they cannot use. Cascade passkey deletion from
the admin user-deletion path so credential IDs are not stranded.
A temporary 2FA token proves only the first factor, so honouring one
minted before a password reset let anyone holding the second factor
survive account recovery. Apply the same credentials-changed cutoff the
JWT strategy uses.

Also distinguish a failed passkey query from an empty list; the error
state previously rendered as "no passkeys yet", which misreports what
is protecting the account.
Returning success on a storage error bypassed the compare-and-swap it
exists to enforce, so a cloned authenticator could be accepted while the
stored counter stayed stale. A database that cannot take this write
cannot mint the session either, so little is gained by failing open.
Counterless credentials carry no clone signal and keep their old path.
A full-page navigation to the 2FA screen remounted AuthContextProvider,
which silent-refreshes on mount; no refresh session exists yet at that
point, so it bounced back to login before the code could be entered.
Route through the router like the password flow does.

Also reveal the removal step-up field when the server refuses a
passwordless attempt, so an account migrated to an identity provider
without its old hash cleared can still clear its credentials; drop the
staged password when the dialog closes; and revoke passkeys in the CLI
password reset, which bypassed the HTTP controller's cleanup.
Accounts predating mandatory verification are marked verified as they
sign in when no email is configured, but only the password strategy did
it, so the same legacy account was admitted by password and refused by
passkey. Extract the rule into a shared helper and call it from both.
checkBan defaults next to a no-op, so calling it bare discarded any
internal failure and left req.banned unset, letting the request fall
through and be issued tokens. Capture the error the middleware chain
would have propagated and reject instead.
@berry-13
berry-13 force-pushed the feat/passkey-auth-ui branch from e23917a to 4d9feb0 Compare August 9, 2026 16:05
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.

2 participants