Skip to content

🔐 feat: Use SecretInput for Sensitive Fields - #12955

Merged
danny-avila merged 10 commits into
devfrom
feat/secret-input-sensitive-fields
Jun 1, 2026
Merged

danny-avila merged 10 commits into
devfrom
feat/secret-input-sensitive-fields

Conversation

@berry-13

@berry-13 berry-13 commented May 5, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Adopts the shared SecretInput across every place we render a sensitive value in the client (API keys, OAuth client secrets, MCP variables, 2FA seed, generated agent keys, auth password fields), then irons out the styling so the component looks the same everywhere it appears.

Closes #11801. Builds on #11582.

What's in here

SecretInput rollout

  • Replaces the ad-hoc password/text inputs with SecretInput in the Set Key dialogs (Custom, Google, OpenAI, Other), MCP custom user vars + MCP server config dialog, MCP builder auth section, agent builder Action auth (basic + bearer + custom OAuth fields), web-search provider keys (Search, Scraper, Reranker), Plugin store auth form, generated agent API keys list, and the 2FA secret display.
  • Auth (login, registration, reset-password) keeps its floating-label layout but now uses SecretInput so the reveal/copy controls match the rest of the app.
  • Non-secret fields (URLs, deployment names, API versions, instance names) are deliberately left as plain Input so the reveal toggle isn't shown where it makes no sense.

Component polish

  • Border default switched to border-border-light; added transition-colors, hover:border-border-medium, and focus-visible:border-border-heavy for clearer keyboard / pointer feedback. Auth pages opt back into focus:border-green-500 + focus-visible:border-green-500 so the green focus border is preserved.
  • Toggle and copy buttons are now size-7 rounded-md with hover:bg-surface-hover, giving a visible affordance on hover and a tighter shape that fits inside the h-10 input.
  • Reveal/copy controls can be hidden until hover/focus via controlsOnHover. Wired into the side-panel and dialog usages where the row is otherwise visually busy.
  • Generic aria-labels ("Show secret" / "Hide secret" / "Copy to clipboard"), autoComplete="off", and spellCheck={false} by default.

Alignment fix

  • The wrapper was flex items-center; flex containers include child margins in the cross-axis size, so passing className="mb-2" (e.g. InputSection.tsx) made the wrapper 48px while the input was 40px. The absolutely-positioned controls inherited the inflated 48px and centered the eye 4px below the input's true center. Wrapper is now a plain relative block — height collapses back to the input and the icon sits dead-center. Verified via DOM measurement: button center Y matches input center Y exactly (was off by 4px).

Files touched

packages/client/src/components/SecretInput.tsx, client/src/components/Auth/{LoginForm,Registration,ResetPassword}.tsx, client/src/components/Chat/Input/MCPConfigDialog.tsx, client/src/components/Input/SetKeyDialog/{InputWithLabel,CustomEndpoint,GoogleConfig,OpenAIConfig,OtherConfig}.tsx, client/src/components/MCP/CustomUserVarsSection.tsx, client/src/components/Nav/SettingsTabs/Account/TwoFactorPhases/QRPhase.tsx, client/src/components/Nav/SettingsTabs/Data/AgentApiKeys.tsx, client/src/components/Plugins/Store/PluginAuthForm.tsx, client/src/components/SidePanel/Agents/Search/InputSection.tsx, client/src/components/SidePanel/Builder/ActionsAuth.tsx, client/src/components/SidePanel/MCPBuilder/MCPServerDialog/sections/AuthSection.tsx, plus the unused password i18n keys removed from client/src/locales/en/translation.json.

Change Type

  • New feature (non-breaking change which adds functionality)
  • Refactoring
  • Style

Testing

Manual pass against the dev frontend (Vite on :3090 with the local backend on :3080), driving the UI through Chromium. For each affected surface I checked: empty state, with a value, focus, hover, reveal toggle, and copy (where applicable), in both light and dark mode.

Surfaces exercised:

  • Auth — login, registration, reset password (typed + revealed; verified the green focus border still shows; Show secret / Hide secret toggle).
  • Set API key dialog — Custom, Google, OpenAI, Other endpoints.
  • MCP — custom user variables panel, MCP server credential dialog (e.g. GitHub PAT), MCP server builder auth section.
  • Agent builder — Action auth (basic, bearer, OAuth secret fields).
  • Web search dialog — Search Provider, Scraper, Reranker keys (the original alignment regression repro case).
  • Settings — generated agent API keys, 2FA secret reveal.
  • Plugin store — generic API key auth form.

Updated unit tests:

  • packages/client/src/components/MCP/__tests__/CustomUserVarsSection.test.tsx
  • client/src/components/Plugins/Store/__tests__/PluginAuthForm.spec.tsx

Test Configuration

  • Node.js v24.1.0
  • Chromium (Playwright)
  • Vite dev server (frontend :3090), Express backend (:3080)

Checklist

  • My code adheres to this project's style guidelines
  • I have performed a self-review of my own code
  • 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
  • Any changes dependent on mine have been merged and published in downstream modules.

Copilot AI review requested due to automatic review settings May 5, 2026 14:29
@github-actions

github-actions Bot commented May 5, 2026

Copy link
Copy Markdown
Contributor

🚨 Unused i18next Keys Detected

The following translation keys are defined in translation.json but are not used in the codebase:

  • com_ui_hide_password
  • com_ui_show_password

⚠️ Please remove these unused keys to keep the translation files clean.

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.

Pull request overview

This PR standardizes handling of sensitive/secret fields across the client UI by adopting the shared SecretInput component (reveal + optional copy) in auth flows and settings dialogs, while keeping non-sensitive fields on the standard Input.

Changes:

  • Enhanced SecretInput styling and added optional internal label support (for floating-label auth forms) with generic “Show secret/Hide secret” reveal labels.
  • Migrated multiple sensitive inputs (auth passwords, agent API key creation display, 2FA secret display, MCP custom user vars, builder action auth fields, and web-search provider key inputs) to use SecretInput.
  • Updated Set Key dialog inputs to support a new secret flag, using SecretInput only for key/secret fields.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/client/src/components/SecretInput.tsx Adds label support, updates border class, and standardizes reveal aria-label text.
client/src/components/SidePanel/Builder/ActionsAuth.tsx Uses SecretInput for API key / OAuth client id/secret fields and refactors conditional rendering.
client/src/components/SidePanel/Agents/Search/InputSection.tsx Replaces custom password-visibility logic with SecretInput for secret inputs.
client/src/components/Nav/SettingsTabs/Data/AgentApiKeys.tsx Uses SecretInput to reveal/copy newly created agent API keys.
client/src/components/Nav/SettingsTabs/Account/TwoFactorPhases/QRPhase.tsx Uses SecretInput to reveal/copy the 2FA secret.
client/src/components/MCP/CustomUserVarsSection.tsx Uses SecretInput for MCP auth vars and improves react-hook-form typing.
client/src/components/MCP/tests/CustomUserVarsSection.test.tsx Updates expectations to match SecretInput behavior (type="password").
client/src/components/Input/SetKeyDialog/OtherConfig.tsx Marks “Other” endpoint key input as secret via secret prop.
client/src/components/Input/SetKeyDialog/OpenAIConfig.tsx Marks OpenAI/Azure API key inputs as secret via secret prop.
client/src/components/Input/SetKeyDialog/InputWithLabel.tsx Adds secret prop and renders SecretInput when enabled; fixes sublabel rendering.
client/src/components/Input/SetKeyDialog/GoogleConfig.tsx Marks Google API key input as secret via secret prop.
client/src/components/Input/SetKeyDialog/CustomEndpoint.tsx Marks custom endpoint API key input as secret via secret prop.
client/src/components/Auth/ResetPassword.tsx Migrates password + confirm password fields to SecretInput while preserving floating-label styling.
client/src/components/Auth/Registration.tsx Uses SecretInput for password fields and keeps floating-label behavior.
client/src/components/Auth/LoginForm.tsx Migrates login password field to SecretInput with floating label.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +81 to +85
{label != null && (
<label htmlFor={id} className={cn(labelClassName ?? '')}>
{label}
</label>
)}
@@ -24,6 +24,7 @@ const OpenAIConfig = ({
label={`${isAzure ? 'Azure q' : ''}OpenAI API Key`}
@github-actions

github-actions Bot commented May 5, 2026

Copy link
Copy Markdown
Contributor

🚨 Unused i18next Keys Detected

The following translation keys are defined in translation.json but are not used in the codebase:

  • com_ui_hide_password
  • com_ui_show_password

⚠️ Please remove these unused keys to keep the translation files clean.

@berry-13
berry-13 marked this pull request as ready for review May 7, 2026 22:28
@danny-avila

Copy link
Copy Markdown
Collaborator

@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: f4814359cb

ℹ️ 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 on lines +81 to +89
<SecretInput
placeholder={config.placeholder}
autoComplete="one-time-code"
data-lpignore="true"
data-1p-ignore="true"
controlsOnHover
className="mb-2"
{...register(name as keyof SearchApiKeyFormData)}
/>

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve localized show/hide labels for secret toggle

Replacing the password field with SecretInput here removes the previously localized toggle labels (com_ui_show_password / com_ui_hide_password) and falls back to SecretInput’s hardcoded English aria-labels (Show secret / Hide secret). In non-English locales this regresses screen-reader UX for this form, so this call site should pass localized labels (or SecretInput should localize them internally) to keep accessibility text translated.

Useful? React with 👍 / 👎.

@jumasheff

Copy link
Copy Markdown

Thanks for this PR. One downstream integration note: MCP customUserVars can include both secret values and non-secret setup values, for example username, project key, URL etc.

With this change, all dynamic MCP variables render as SecretInput, which is safer by default, but it also masks non-secret fields which looks unconventional.

Would you be open to an optional per-field hint in customUserVars, e.g. type: "password" | "text" or sensitive: boolean?

@danny-avila

Copy link
Copy Markdown
Collaborator

@berry-13 I think @jumasheff's comment is worth implementing before merge

@berry-13

Copy link
Copy Markdown
Collaborator Author

Thanks for this PR. One downstream integration note: MCP customUserVars can include both secret values and non-secret setup values, for example username, project key, URL etc.

With this change, all dynamic MCP variables render as SecretInput, which is safer by default, but it also masks non-secret fields which looks unconventional.

Would you be open to an optional per-field hint in customUserVars, e.g. type: "password" | "text" or sensitive: boolean?

agree, working on this now

berry-13 added 10 commits May 30, 2026 23:49
The wrapper was a flex container, so passing 'mb-2' on the input made it
contribute its margin to the wrapper's cross-axis size — the controls overlay
spanned the inflated height and centered the toggle 4px below the input's
true center. Switching the wrapper to a plain relative block collapses height
back to the input.

Also tightens the toggle/copy buttons (size-7 rounded-md with hover:bg-surface-hover)
and adds a focus ring on the input. Auth pages still override className/buttonClassName
so login/register styling is unchanged.
SecretInput's modernized default uses focus-visible:border-border-heavy and
hover:border-border-medium, which Tailwind emits after the auth pages' focus:
rules and overrides them. Auth pages now also declare focus-visible:border-green-500
and hover:border-border-light so cn()/twMerge resolves them as the winners
when classes are concatenated.
Dynamic MCP credential fields all rendered as masked SecretInputs, which
also hid non-secret setup values like usernames, project keys, and URLs.

Add an optional `sensitive` flag to customUserVars and the plugin auth
config. It defaults to masked when omitted, so existing configs keep the
safe-by-default behavior; set `sensitive: false` to render a field as
plain text. The flag is display-only — values remain encrypted at rest.
@berry-13
berry-13 force-pushed the feat/secret-input-sensitive-fields branch from 61406e3 to 6474c84 Compare May 30, 2026 22:11
@danny-avila

Copy link
Copy Markdown
Collaborator

@codex review

@danny-avila danny-avila changed the title 🔐 feat: Use SecretInput for Sensitive Fields 🔐 feat: Use SecretInput for Sensitive Fields Jun 1, 2026
@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. More of your lovely PRs please.

ℹ️ 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".

@danny-avila
danny-avila merged commit 730878b into dev Jun 1, 2026
17 checks passed
@danny-avila
danny-avila deleted the feat/secret-input-sensitive-fields branch June 1, 2026 22:14
fuuuzzy pushed a commit to fuuuzzy/LibreChat that referenced this pull request Jun 4, 2026
* feat: use SecretInput for sensitive fields

* fix: align auth SecretInput styles

* chore: remove unused password i18n keys

* fix: align SecretInput controls

* fix: use SecretInput for dynamic credentials

* fix: reveal SecretInput controls on hover

* fix: align SecretInput eye icon and modernize controls

The wrapper was a flex container, so passing 'mb-2' on the input made it
contribute its margin to the wrapper's cross-axis size — the controls overlay
spanned the inflated height and centered the toggle 4px below the input's
true center. Switching the wrapper to a plain relative block collapses height
back to the input.

Also tightens the toggle/copy buttons (size-7 rounded-md with hover:bg-surface-hover)
and adds a focus ring on the input. Auth pages still override className/buttonClassName
so login/register styling is unchanged.

* fix: remove focus ring from SecretInput

* fix: keep green focus border on auth secret inputs

SecretInput's modernized default uses focus-visible:border-border-heavy and
hover:border-border-medium, which Tailwind emits after the auth pages' focus:
rules and overrides them. Auth pages now also declare focus-visible:border-green-500
and hover:border-border-light so cn()/twMerge resolves them as the winners
when classes are concatenated.

* feat: add optional sensitive flag to MCP customUserVars

Dynamic MCP credential fields all rendered as masked SecretInputs, which
also hid non-secret setup values like usernames, project keys, and URLs.

Add an optional `sensitive` flag to customUserVars and the plugin auth
config. It defaults to masked when omitted, so existing configs keep the
safe-by-default behavior; set `sensitive: false` to render a field as
plain text. The flag is display-only — values remain encrypted at rest.
ThomasVuNguyen pushed a commit to ThomasVuNguyen/LibreChat that referenced this pull request Jul 15, 2026
* feat: use SecretInput for sensitive fields

* fix: align auth SecretInput styles

* chore: remove unused password i18n keys

* fix: align SecretInput controls

* fix: use SecretInput for dynamic credentials

* fix: reveal SecretInput controls on hover

* fix: align SecretInput eye icon and modernize controls

The wrapper was a flex container, so passing 'mb-2' on the input made it
contribute its margin to the wrapper's cross-axis size — the controls overlay
spanned the inflated height and centered the toggle 4px below the input's
true center. Switching the wrapper to a plain relative block collapses height
back to the input.

Also tightens the toggle/copy buttons (size-7 rounded-md with hover:bg-surface-hover)
and adds a focus ring on the input. Auth pages still override className/buttonClassName
so login/register styling is unchanged.

* fix: remove focus ring from SecretInput

* fix: keep green focus border on auth secret inputs

SecretInput's modernized default uses focus-visible:border-border-heavy and
hover:border-border-medium, which Tailwind emits after the auth pages' focus:
rules and overrides them. Auth pages now also declare focus-visible:border-green-500
and hover:border-border-light so cn()/twMerge resolves them as the winners
when classes are concatenated.

* feat: add optional sensitive flag to MCP customUserVars

Dynamic MCP credential fields all rendered as masked SecretInputs, which
also hid non-secret setup values like usernames, project keys, and URLs.

Add an optional `sensitive` flag to customUserVars and the plugin auth
config. It defaults to masked when omitted, so existing configs keep the
safe-by-default behavior; set `sensitive: false` to render a field as
plain text. The flag is display-only — values remain encrypted at rest.
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.

4 participants