馃攽 feat: Passkey Authentication with WebAuthn Sign-In and Management - #14715
馃攽 feat: Passkey Authentication with WebAuthn Sign-In and Management#14715berry-13 wants to merge 9 commits into
Conversation
|
@codex review |
There was a problem hiding this comment.
馃挕 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".
7ba7cac to
03b971b
Compare
|
@codex review |
There was a problem hiding this comment.
馃挕 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".
03b971b to
b293f9f
Compare
|
@codex review |
There was a problem hiding this comment.
馃挕 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".
|
@codex review |
8e28329 to
7bc957e
Compare
|
@codex review |
There was a problem hiding this comment.
馃挕 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".
|
@codex review |
There was a problem hiding this comment.
馃挕 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".
|
@codex review |
There was a problem hiding this comment.
馃挕 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".
|
@codex review |
There was a problem hiding this comment.
馃挕 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".
|
@codex review |
There was a problem hiding this comment.
馃挕 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".
|
@codex review |
|
Codex Review: Didn't find any major issues. Breezy! Reviewed commit: 鈩癸笍 About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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.
e23917a to
4d9feb0
Compare
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_LOGINand 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 newpasskeyscollection that cascades on account deletion.Account protections included in this PR:
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
credentialsChangedAtmarker 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/serverand@simplewebauthn/browser.Change Type
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, sincepackages/data-schemasgains a field), then start the backend and frontend.Exercised against a running instance:
POST /api/auth/passkey/register/optionswith 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./api/user, then 401 once a credential change is recorded, while a freshly issued token continues to work.redirect_tocannot move the post-login destination off-origin, and that ordinary in-app redirect targets are still honoured.aria-invalid, pointsaria-describedbyat arole="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:
ALLOW_PASSKEY_LOGIN=true,ALLOW_EMAIL_LOGIN=true,ALLOW_PASSWORD_RESET=trueDOMAIN_CLIENTNew configuration introduced by this PR:
ALLOW_PASSKEY_LOGINPASSKEY_RP_ID/PASSKEY_RP_NAME/PASSKEY_ORIGINSDOMAIN_CLIENTandDOMAIN_SERVERPASSKEY_MAX/PASSKEY_WINDOWPASSKEY_STEPUP_MAX/PASSKEY_STEPUP_WINDOWChecklist