Skip to content

Add local account management controls#978

Open
CoderLuii wants to merge 1 commit into
siteboon:mainfrom
CoderLuii:agent/local-account-management
Open

Add local account management controls#978
CoderLuii wants to merge 1 commit into
siteboon:mainfrom
CoderLuii:agent/local-account-management

Conversation

@CoderLuii

@CoderLuii CoderLuii commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds local account controls for self-hosted CloudCLI installs:

  • Account settings tab with Logout and Change Password controls
  • POST /api/auth/change-password for local password rotation
  • token-generation tracking so old REST, query-token, SSE, and WebSocket tokens are rejected after a password change
  • platform-mode guard so hosted/platform deployments do not expose local password management

Why

Local installs can create an account during setup, but there is no UI path to log out or rotate that password afterward. The practical workaround becomes deleting local auth state, which is risky and easy to get wrong.

This keeps the existing single-user local model intact while adding the missing account-management path.

Validation

  • npm ci
  • npm run typecheck
  • npm run build
  • npm run lint exits 0 with existing warnings

Fixes #797.

Summary by CodeRabbit

  • New Features

    • Added an Account section in Settings with a change-password form and logout access.
    • Users can now update their password from within the app.
    • Sign-in sessions are now refreshed after a password change, requiring users to sign in again.
  • Bug Fixes

    • Strengthened authentication so old tokens stop working after password-related changes.
    • Improved account settings navigation and labels to surface the new Account area more clearly.

@coderabbitai

coderabbitai Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds server-side JWT token generation invalidation, a new change-password backend route with supporting repository methods, and a client-facing Account settings tab enabling password changes and logout, wired through updated auth context, API utilities, and settings navigation.

Changes

Account Settings and Change Password

Layer / File(s) Summary
JWT token generation invalidation
server/middleware/auth.js
Adds a persisted token generation check to REST and WebSocket JWT verification and embeds the current generation into newly issued tokens.
Repository support
server/modules/database/repositories/app-config.ts, server/modules/database/repositories/users.ts
Adds a strict config read that propagates errors, plus user methods to fetch auth data by id and update password hashes for active users.
Change-password route
server/routes/auth.js
Adds authenticated POST /change-password route validating fields, current password, and platform mode, updates the password hash, and rotates the token generation in a transaction; registration reuses a shared minimum length constant.
Frontend auth/API wiring
src/utils/api.js, src/components/auth/types.ts, src/components/auth/context/AuthContext.tsx
Adds api.auth.changePassword, a changePassword context callback handling success/error and session clearing, and the corresponding AuthContextValue type.
Settings navigation
src/components/settings/types/types.ts, src/components/settings/constants/constants.ts, src/components/settings/view/Settings.tsx, src/components/settings/view/SettingsMainTabs.tsx, src/components/settings/view/SettingsSidebar.tsx
Replaces the 'agents' tab with an 'account' tab using the CircleUserRound icon and adds sidebar support for literal labels alongside translation keys.
AccountSettingsTab component
src/components/settings/view/tabs/AccountSettingsTab.tsx
Adds a new tab with password form validation, submission logic, logout button, and platform-mode-aware UI.

Sequence Diagram(s)

sequenceDiagram
  participant AccountSettingsTab
  participant AuthContext
  participant ChangePasswordRoute
  participant UserDb
  participant AppConfigDb
  AccountSettingsTab->>AuthContext: changePassword(currentPassword, newPassword)
  AuthContext->>ChangePasswordRoute: POST /api/auth/change-password
  ChangePasswordRoute->>UserDb: getUserAuthById(userId)
  ChangePasswordRoute->>ChangePasswordRoute: verify currentPassword
  ChangePasswordRoute->>UserDb: updatePasswordHash(userId, newHash)
  ChangePasswordRoute->>AppConfigDb: write new AUTH_TOKEN_GENERATION_KEY
  ChangePasswordRoute-->>AuthContext: success response
  AuthContext->>AuthContext: clearSession()
Loading

Poem

A rabbit hops to settings new,
Found a logout button too! 🐰
Passwords change, old tokens fade,
New generation, freshly made.
Hop, hop, sign out, sign back in—
Secure burrows, safe within! ✨

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The PR includes substantial password-change and token-invalidation work beyond the linked logout-button request. Split the logout-button fix from the account-password and auth-token changes, or add linked issues covering the broader scope.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is clear and matches the main theme of local account-related UI changes.
Linked Issues check ✅ Passed The PR adds a visible logout button in the settings UI, satisfying the directly linked #797 requirement.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 2

🧹 Nitpick comments (2)
server/routes/auth.js (1)

38-40: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Message text drifts from PASSWORD_MIN_LENGTH.

The validations use PASSWORD_MIN_LENGTH, but the error strings hardcode "6 characters" (Line 39 and Line 148). If the constant changes, the messages will be misleading. Consider interpolating the constant.

♻️ Interpolate the constant
-      return res.status(400).json({ error: 'New password must be at least 6 characters' });
+      return res.status(400).json({ error: `New password must be at least ${PASSWORD_MIN_LENGTH} characters` });

Line 39 (registration) can be updated similarly.

Also applies to: 147-149

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/routes/auth.js` around lines 38 - 40, The validation error messages in
the auth flow are hardcoding the password length instead of reflecting
PASSWORD_MIN_LENGTH. Update the response strings in the registration and related
checks within auth.js to interpolate PASSWORD_MIN_LENGTH so the message stays
aligned with the actual validation logic. Use the existing validation branches
around the username/password checks and keep the wording consistent across both
occurrences.
src/components/settings/view/tabs/AccountSettingsTab.tsx (1)

28-30: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Reuse a shared minimum-length constant instead of hardcoding 6.

The length check and its message hardcode 6, while the server validates against PASSWORD_MIN_LENGTH (server/routes/auth.js). If that constant changes, this client validation and copy silently drift out of sync. Consider importing/deriving a shared constant and interpolating it into the message.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/settings/view/tabs/AccountSettingsTab.tsx` around lines 28 -
30, The password validation in AccountSettingsTab is hardcoding the minimum
length, which can drift from the server’s PASSWORD_MIN_LENGTH. Update the logic
in the validation flow that checks formState.newPassword so it uses a shared
minimum-length constant instead of a literal 6, and make the returned error
message interpolate that same constant. Keep the client-side check and copy
aligned with the server-side password rule.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/settings/types/types.ts`:
- Line 6: The settings tab normalization is missing the new 'account' tab, so
URL/command-palette navigation falls back to 'agents' instead of opening
account. Update the KNOWN_MAIN_TABS array in useSettingsController.ts to include
'account' so normalizeMainTab recognizes it, and keep it aligned with the
SettingsMainTab union in types.ts.

In `@src/components/settings/view/tabs/AccountSettingsTab.tsx`:
- Around line 153-157: The error message in AccountSettingsTab is only visible
and not announced to assistive tech. Update the error container rendered in the
error && block to use an alert announcement pattern, such as adding role="alert"
or an appropriate aria-live region, so validation and submission failures are
surfaced by screen readers. Keep the change localized to the error UI in
AccountSettingsTab.

---

Nitpick comments:
In `@server/routes/auth.js`:
- Around line 38-40: The validation error messages in the auth flow are
hardcoding the password length instead of reflecting PASSWORD_MIN_LENGTH. Update
the response strings in the registration and related checks within auth.js to
interpolate PASSWORD_MIN_LENGTH so the message stays aligned with the actual
validation logic. Use the existing validation branches around the
username/password checks and keep the wording consistent across both
occurrences.

In `@src/components/settings/view/tabs/AccountSettingsTab.tsx`:
- Around line 28-30: The password validation in AccountSettingsTab is hardcoding
the minimum length, which can drift from the server’s PASSWORD_MIN_LENGTH.
Update the logic in the validation flow that checks formState.newPassword so it
uses a shared minimum-length constant instead of a literal 6, and make the
returned error message interpolate that same constant. Keep the client-side
check and copy aligned with the server-side password rule.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8d89ef01-1cf3-4fa2-927e-8de224179af0

📥 Commits

Reviewing files that changed from the base of the PR and between 5884573 and 60c9003.

📒 Files selected for processing (13)
  • server/middleware/auth.js
  • server/modules/database/repositories/app-config.ts
  • server/modules/database/repositories/users.ts
  • server/routes/auth.js
  • src/components/auth/context/AuthContext.tsx
  • src/components/auth/types.ts
  • src/components/settings/constants/constants.ts
  • src/components/settings/types/types.ts
  • src/components/settings/view/Settings.tsx
  • src/components/settings/view/SettingsMainTabs.tsx
  • src/components/settings/view/SettingsSidebar.tsx
  • src/components/settings/view/tabs/AccountSettingsTab.tsx
  • src/utils/api.js

import type { ProviderAuthStatus } from '../../provider-auth/types';

export type SettingsMainTab = 'agents' | 'appearance' | 'git' | 'api' | 'voice' | 'tasks' | 'browser' | 'notifications' | 'plugins' | 'about';
export type SettingsMainTab = 'account' | 'agents' | 'appearance' | 'git' | 'api' | 'voice' | 'tasks' | 'browser' | 'notifications' | 'plugins' | 'about';

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.

🗄️ Data Integrity & Integration | 🔴 Critical | ⚡ Quick win

KNOWN_MAIN_TABS in useSettingsController.ts does not include 'account', making the tab unreachable via URL/command-palette normalization.

The SettingsMainTab type now includes 'account', but the upstream controller's KNOWN_MAIN_TABS array (in src/components/settings/hooks/useSettingsController.ts:54) is still ['agents', 'appearance', 'git', 'api', 'tasks', 'browser', 'notifications', 'plugins', 'about']'account' is missing. The normalizeMainTab function falls back to 'agents' for any tab not in that array. This means:

  1. Opening settings with ?tab=account (e.g., via the command palette, which calls onOpenSettings('account')) will silently redirect to the 'agents' tab.
  2. The account tab will only work when activated by clicking the sidebar/main-tab button directly (bypassing normalization), creating inconsistent behavior.

Update KNOWN_MAIN_TABS to include 'account':

-const KNOWN_MAIN_TABS: SettingsMainTab[] = ['agents', 'appearance', 'git', 'api', 'tasks', 'browser', 'notifications', 'plugins', 'about'];
+const KNOWN_MAIN_TABS: SettingsMainTab[] = ['account', 'agents', 'appearance', 'git', 'api', 'tasks', 'browser', 'notifications', 'plugins', 'about'];
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/settings/types/types.ts` at line 6, The settings tab
normalization is missing the new 'account' tab, so URL/command-palette
navigation falls back to 'agents' instead of opening account. Update the
KNOWN_MAIN_TABS array in useSettingsController.ts to include 'account' so
normalizeMainTab recognizes it, and keep it aligned with the SettingsMainTab
union in types.ts.

Comment on lines +153 to +157
{error && (
<div className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-red-900/50 dark:bg-red-950/30 dark:text-red-200">
{error}
</div>
)}

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.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Announce the error to assistive tech.

The error container is rendered visually but isn't announced to screen readers. Add role="alert" (or an aria-live region) so validation and submission failures are surfaced.

♿ Proposed a11y fix
-                  {error && (
-                    <div className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-red-900/50 dark:bg-red-950/30 dark:text-red-200">
+                  {error && (
+                    <div role="alert" className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-red-900/50 dark:bg-red-950/30 dark:text-red-200">
                       {error}
                     </div>
                   )}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
{error && (
<div className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-red-900/50 dark:bg-red-950/30 dark:text-red-200">
{error}
</div>
)}
{error && (
<div role="alert" className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-red-900/50 dark:bg-red-950/30 dark:text-red-200">
{error}
</div>
)}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/settings/view/tabs/AccountSettingsTab.tsx` around lines 153 -
157, The error message in AccountSettingsTab is only visible and not announced
to assistive tech. Update the error container rendered in the error && block to
use an alert announcement pattern, such as adding role="alert" or an appropriate
aria-live region, so validation and submission failures are surfaced by screen
readers. Keep the change localized to the error UI in AccountSettingsTab.

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.

Missing Logout Button in UI

1 participant