BTST
PluginsQuickstartDocs
Live Blog

From research to product evaluation

Evaluating a publishing workflow for an app you already own?

See what the BTST Blog plugin adds to an existing React or Next.js app
BTST

Open-source TypeScript features for the React application, data, and deployment you already own.

Released plugins

  • Blog
  • AI Chat
  • CMS
  • Form Builder
  • UI Builder
  • Kanban
  • Comments
  • Media
  • Route Docs
  • OpenAPI
  • Better Auth UI

Resources

  • Quickstart
  • Documentation
  • All plugins
  • Live Blog
  • GitHub (opens in a new tab)
© 2026 BTST. Open source under the MIT License.
AI Chat
September 18, 2026ReactBetter Auth UI

Confirm Account Deletion with BTST Better Auth UI

Align server deletion policy, email confirmation, and BTST account controls, then verify sessions and application cleanup.

Confirm Account Deletion with BTST Better Auth UI

BTST's delete-account dialog starts an account-removal request. The server must separately enable deletion, verify the caller, and decide what happens to application data. If confirmation by email is required, configure both the server callback and the UI's pending-confirmation state.

This guide targets @btst/better-auth-ui@2.0.1, @btst/stack@3.1.2, and better-auth@1.6.16. It assumes the auth and account pages already work. Use disposable accounts when testing; a completed deletion is a destructive operation.

Decide what deletion includes#

Before enabling the control, inspect the data related to a user ID: authentication records, organization membership, authored content, uploads, billing references, and external services. Better Auth's account endpoint does not define a retention policy or automatically erase every record your application owns.

Choose explicitly whether authored content is retained, anonymized, transferred, or removed. Resolve sole-owner organizations and active subscriptions according to the product's rules. Do not make a browser dialog responsible for enforcing those rules: another client can call the endpoint directly.

The pinned server deletion implementation invokes beforeDelete before removal and afterDelete afterward. Use these server hooks where appropriate, but do not assume external cleanup and database deletion form one atomic transaction. A failure after removal needs a durable, retryable cleanup process. Verify your actual adapter's relations and constraints before relying on cascades.

Require a confirmation message on the server#

Merge this fragment into the existing Better Auth options, preserving other user settings:

TS
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
import type { BetterAuthOptions } from "better-auth";
import { after } from "next/server";
import { sendEmail } from "@/lib/email";

export const deletionPolicy = {
  user: {
    deleteUser: {
      enabled: true,
      sendDeleteAccountVerification: async ({ user, url }) => {
        after(async () => {
          await sendEmail({
            to: user.email,
            subject: "Confirm account deletion",
            text: `Confirm removal of your account: ${url}`,
          });
        });
      },
    },
  },
} satisfies BetterAuthOptions;

sendEmail is your existing delivery adapter. after is the Next.js request-lifecycle mechanism here; use your host's equivalent outside Next.js. Delivery monitoring must omit the link and token. In a product where email ownership matters for this decision, require verified addresses through the existing registration and account policies.

With this callback, a successful initial request reports that verification was sent. The user still exists at that point. The generated URL invokes Better Auth's deletion callback when opened; its callback URL controls navigation afterward, not where verification occurs. Preserve the generated URL and the endpoint's origin checks.

In the pinned release, completing that callback requires a session for the same user as the token. Opening the message in an unrelated browser or while signed in as another user does not authorize deletion. Make that requirement clear in your help text and test it across devices. See Better Auth's account documentation for the broader flow.

Enable the matching BTST dialog state#

Merge the following into the existing StackProvider overrides.account value:

TS
  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
import type { AccountPluginOverrides } from "@btst/better-auth-ui/client";

export const deletionUI = {
  deleteUser: { verification: true },
} satisfies Partial<AccountPluginOverrides>;

With default paths under /p, the card appears at /p/account/security. The released dialog asks credential users for a password. For an account without a linked password, it sends a stale session through sign-out before retrying. Keep the companion's freshAge aligned with the server policy.

The UI's verification flag changes its confirmation message and callback navigation. It does not make the server send email. If that UI flag is enabled while the server callback is missing, the server may complete deletion immediately under its ordinary password or fresh-session rules while the interface says to check email. Conversely, configuring the server callback while leaving the UI in immediate-deletion mode gives misleading feedback. Test the pair together.

Test pending, rejected, and completed requests#

Use two disposable accounts and a separate browser session:

ActionWhat to verify
Call without a sessionThe server rejects the request
Submit an incorrect passwordThe account remains and no deletion message is sent
Submit a valid requestConfirmation is sent; user, sessions, and application data still exist
Open the link without its user's sessionDeletion is refused
Open it as the other accountNeither account is removed
Open an expired tokenDeletion is refused
Complete with the correct accountAuth records and sessions are removed as expected; application cleanup follows its defined policy
Reuse the completed tokenIt cannot delete another account

After completion, test protected server access using every previously active test session. Account removal must be reflected in server authorization, not merely in the current tab. Review any application-managed session or permission cache separately.

Do not report all data erased because the auth row disappeared. Keep a separate verification record for the application records and external effects your policy requires. Likewise, successful email scheduling is not confirmed delivery or completed deletion.

The snippets were type-checked and the pinned auth handler was tested with an in-memory adapter and captured email callbacks. These checks cover confirmation and access conditions; real delivery, production database constraints, billing or storage cleanup, and the complete browser flow were not exercised. Continue with session management and organization setup when reviewing the related account lifecycle.

In This Post

Decide what deletion includesRequire a confirmation message on the serverEnable the matching BTST dialog stateTest pending, rejected, and completed requests