Resolves discussion #291 — the app exposes Better Auth's change-password / change-email endpoints server-side but had no UI to reach them.
Avatar dropdown in the header now shows user info + Change password + Change email + Logout
Each item opens a small dialog that calls authClient.changePassword / authClient.changeEmail directly — no new API routes
Change password is hidden for SSO-only users (users with no credential provider account). Probe via GET /api/auth/list-accounts; fails open so a transient probe error doesn't lock anyone out of changing their password.
Enables user.changeEmail.enabled = true with updateEmailWithoutVerification: true in src/lib/auth.ts — safe because requireEmailVerification is already off and the project has no email sender wired up.
Test plan
End-to-end browser test (Playwright against the dev server) — all passed:
Fresh signup → dropdown renders with user info, Change password, Change email, Logout
Mismatched new/confirm password → validation toast, dialog stays open
Valid password change → success toast, dialog closes, log out + log back in with new password works
Email change → success toast, dropdown immediately shows new email (refreshUser), DB row updated, log in with new email works
revokeOtherSessions: true checkbox → verified a second session (curl-issued cookie) is invalidated on the next request after the change; current browser session stays alive
bun run build — clean
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.
## 📋 Pull Request Information
**Original PR:** https://github.com/RayLabsHQ/gitea-mirror/pull/292
**Author:** [@arunavo4](https://github.com/arunavo4)
**Created:** 5/19/2026
**Status:** ✅ Merged
**Merged:** 5/19/2026
**Merged by:** [@arunavo4](https://github.com/arunavo4)
**Base:** `main` ← **Head:** `feat/account-menu`
---
### 📝 Commits (1)
- [`fb7ca88`](https://github.com/RayLabsHQ/gitea-mirror/commit/fb7ca88ba060fd313fbb83cee345ff3a4e77f223) feat: add Change password and Change email to account dropdown
### 📊 Changes
**5 files changed** (+412 additions, -43 deletions)
<details>
<summary>View changed files</summary>
➕ `src/components/auth/AccountMenu.tsx` (+134 -0)
➕ `src/components/auth/ChangeEmailDialog.tsx` (+110 -0)
➕ `src/components/auth/ChangePasswordDialog.tsx` (+158 -0)
📝 `src/components/layout/Header.tsx` (+4 -43)
📝 `src/lib/auth.ts` (+6 -0)
</details>
### 📄 Description
## Summary
Resolves [discussion #291](https://github.com/RayLabsHQ/gitea-mirror/discussions/291) — the app exposes Better Auth's `change-password` / `change-email` endpoints server-side but had no UI to reach them.
- Avatar dropdown in the header now shows **user info** + **Change password** + **Change email** + Logout
- Each item opens a small dialog that calls `authClient.changePassword` / `authClient.changeEmail` directly — no new API routes
- **Change password is hidden for SSO-only users** (users with no `credential` provider account). Probe via `GET /api/auth/list-accounts`; fails open so a transient probe error doesn't lock anyone out of changing their password.
- Enables `user.changeEmail.enabled = true` with `updateEmailWithoutVerification: true` in `src/lib/auth.ts` — safe because `requireEmailVerification` is already off and the project has no email sender wired up.
## Test plan
End-to-end browser test (Playwright against the dev server) — all passed:
- [x] Fresh signup → dropdown renders with user info, Change password, Change email, Logout
- [x] Mismatched new/confirm password → validation toast, dialog stays open
- [x] Valid password change → success toast, dialog closes, log out + log back in with new password works
- [x] Email change → success toast, dropdown immediately shows new email (`refreshUser`), DB row updated, log in with new email works
- [x] `revokeOtherSessions: true` checkbox → verified a second session (curl-issued cookie) is invalidated on the next request after the change; current browser session stays alive
- [x] `bun run build` — clean
---
<sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
📋 Pull Request Information
Original PR: https://github.com/RayLabsHQ/gitea-mirror/pull/292
Author: @arunavo4
Created: 5/19/2026
Status: ✅ Merged
Merged: 5/19/2026
Merged by: @arunavo4
Base:
main← Head:feat/account-menu📝 Commits (1)
fb7ca88feat: add Change password and Change email to account dropdown📊 Changes
5 files changed (+412 additions, -43 deletions)
View changed files
➕
src/components/auth/AccountMenu.tsx(+134 -0)➕
src/components/auth/ChangeEmailDialog.tsx(+110 -0)➕
src/components/auth/ChangePasswordDialog.tsx(+158 -0)📝
src/components/layout/Header.tsx(+4 -43)📝
src/lib/auth.ts(+6 -0)📄 Description
Summary
Resolves discussion #291 — the app exposes Better Auth's
change-password/change-emailendpoints server-side but had no UI to reach them.authClient.changePassword/authClient.changeEmaildirectly — no new API routescredentialprovider account). Probe viaGET /api/auth/list-accounts; fails open so a transient probe error doesn't lock anyone out of changing their password.user.changeEmail.enabled = truewithupdateEmailWithoutVerification: trueinsrc/lib/auth.ts— safe becauserequireEmailVerificationis already off and the project has no email sender wired up.Test plan
End-to-end browser test (Playwright against the dev server) — all passed:
refreshUser), DB row updated, log in with new email worksrevokeOtherSessions: truecheckbox → verified a second session (curl-issued cookie) is invalidated on the next request after the change; current browser session stays alivebun run build— clean🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.