# Account Deletion Policies

> Customize account deletion authorization rules.

*Canonical: https://makerkit.dev/docs/tanstack-prisma/personal-accounts/authorization-policies*

---

Account deletion policies control when users can delete their accounts. The system ships with default policies that can be extended or replaced.

## Default Policies

The `@kit/account-hooks` package includes two default policies, defined under `packages/account/hooks/src/policies/`:

| Policy | ID | Behavior |
|--------|-----|----------|
| `checkSubscriptionsPolicy` | `account-deletion.check-subscriptions` | Blocks if user has active subscriptions |
| `checkOrganizationsPolicy` | `account-deletion.check-organizations` | Blocks if sole owner of orgs with other members |

> The package root (`@kit/account-hooks`) only re-exports the hook functions `beforeAccountDelete`, `afterAccountDelete`, `cascadeDeleteOwnedOrganizations`, and `checkAccountDeletionEligibility`. The policy symbols below (`AccountDeleteContext`, `accountDeletionRegistry`, `accountDeletion`, `checkSubscriptionsPolicy`, `checkOrganizationsPolicy`) live in the package's internal `./policies` module and are not exported from the root. To customize, edit inside the package (e.g. `src/policies/registry.ts`) or add a subpath export.

## Adding Custom Policies

### 1. Create Your Policy

```typescript
// Inside packages/account/hooks/src/policies/
import { definePolicy, allow, deny } from '@kit/policies';
import type { AccountDeleteContext } from './types';

export const gracePeriodPolicy = definePolicy<AccountDeleteContext>({
  id: 'account-deletion.grace-period',
  evaluate: async (context) => {
    const user = await getUser(context.userId);
    const daysSinceCreation = daysBetween(user.createdAt, new Date());

    if (daysSinceCreation < 7) {
      return deny({
        code: 'ACCOUNT_TOO_NEW',
        message: 'Accounts must be at least 7 days old before deletion',
        remediation: `Please wait ${7 - daysSinceCreation} more days`,
      });
    }

    return allow();
  },
});
```

### 2. Register Your Policy

Extend the default registry:

```typescript
// In packages/account/hooks/src/policies/registry.ts
import { accountDeletionRegistry } from './registry';
import { gracePeriodPolicy } from './grace-period.policy';

// Add to existing defaults
accountDeletionRegistry.registerPolicy(gracePeriodPolicy);
```

## Context Type

```typescript
interface AccountDeleteContext {
  userId: string;      // User attempting to delete account
  timestamp: string;   // ISO timestamp
}
```

## Customization Patterns

### Use Defaults As-Is

```typescript
// From within the package (e.g. before-delete.ts)
import { accountDeletion } from './policies';

const result = await accountDeletion.run({
  userId: user.id,
  timestamp: new Date().toISOString(),
});
```

### Extend Defaults

```typescript
// From within the package
import { accountDeletionRegistry } from './policies';
import { myCustomPolicy } from './my-custom.policy';

accountDeletionRegistry.registerPolicy(myCustomPolicy);
```

### Cherry-Pick Policies

```typescript
import { createPolicyRegistry, createPolicyRuntime } from '@kit/policies';
import { checkOrganizationsPolicy } from './policies';

const registry = createPolicyRegistry();
// Only check organizations, skip subscriptions
registry.registerPolicy(checkOrganizationsPolicy);

const runtime = createPolicyRuntime(registry);
```

### Replace a Policy

```typescript
import { createPolicyRegistry, createPolicyRuntime } from '@kit/policies';
import { checkOrganizationsPolicy } from './policies';
import { mySubscriptionPolicy } from './my-subscription.policy';

const registry = createPolicyRegistry();
registry.registerPolicy(checkOrganizationsPolicy);
registry.registerPolicy(mySubscriptionPolicy); // Your replacement

const runtime = createPolicyRuntime(registry);
```

## Example: Auto-Cancel Subscriptions

Instead of blocking deletion, auto-cancel subscriptions:

```typescript
import { definePolicy, allow } from '@kit/policies';

export const autoCancelPolicy = definePolicy<AccountDeleteContext>({
  id: 'account-deletion.auto-cancel-subscriptions',
  evaluate: async (context) => {
    const subscriptions = await getActiveSubscriptions(context.userId);

    for (const sub of subscriptions) {
      await cancelSubscription(sub.id);
    }

    return allow({
      cancelledSubscriptions: subscriptions.length,
    });
  },
});
```

## Example: Require Data Export

```typescript
export const dataExportPolicy = definePolicy<AccountDeleteContext>({
  id: 'account-deletion.require-export',
  evaluate: async (context) => {
    const hasExported = await checkDataExportStatus(context.userId);

    if (!hasExported) {
      return deny({
        code: 'DATA_NOT_EXPORTED',
        message: 'Please export your data before deleting your account',
        remediation: 'Go to Settings > Privacy > Export Data',
      });
    }

    return allow();
  },
});
```

## Integration

The policies are evaluated in the Better Auth `beforeDeleteUser` hook:

```typescript
// packages/account/hooks/src/before-delete.ts
import { accountDeletion } from './policies';

export async function beforeAccountDelete(userId: string, userEmail?: string) {
  const result = await accountDeletion.run({
    userId,
    timestamp: new Date().toISOString(),
  });

  if (!result.allowed) {
    throw new Error(result.reasons.join(' '));
  }
}
```

---

**Next:** [Preferences →](./preferences)
