npm package: @samueleoraziodurante/better-auth-gdpr
Description: Better Auth plugin to elegantly handle dynamic GDPR and TOS consents
Author: Samuele Orazio Durante
Latest version: 1.0.0

# Better Auth GDPR Plugin

A powerful and dynamic plugin for [Better Auth](https://better-auth.com/) to seamlessly handle GDPR, Terms of Service, and custom consent flags during user registration.

## Why this plugin?

When using complex authentication methods in Better Auth (like the **OPAQUE** protocol or **Passkeys**), injecting custom fields into the sign-up payload can be tricky due to strict type checking and network constraints.

This plugin solves the problem elegantly:

1. **Dynamic Schema:** Define any custom boolean fields you need (e.g., `privacyPolicy`, `newsletter`, `ageConsent`).
2. **Body Injection:** It intercepts the frontend request and securely injects your consents into the JSON body.
3. **Server-Side Enforcement:** It validates the required fields on the server _before_ creating the user.
4. **100% Type-Safe:** Fully compatible with `$InferServerPlugin`, meaning your database schema and frontend client are automatically typed.

## Installation

```bash
npm install better-auth-gdpr
# or
yarn add better-auth-gdpr
# or
pnpm add better-auth-gdpr
# or
bun add better-auth-gdpr
```

## 1. Server Setup

Import the `gdprPlugin` in your server-side `auth.ts` file. You can define as many custom consent fields as you want. Set `required: true` if the user _must_ accept them to register.

```typescript
// server/auth.ts
import { betterAuth } from "better-auth";
import { gdprPlugin } from "better-auth-gdpr";

export const auth = betterAuth({
  database: /* your db config */,
  plugins: [
    gdprPlugin({
      termsOfService: { required: true },
      privacyPolicy: { required: true },
      newsletter: { required: false, defaultValue: false }, // Optional!
      isOver18: { required: true }
    }),
    // ... your other plugins (opaque, passkey, etc.)
  ]
});
```

### Update your Database

Since the plugin dynamically adds these fields to your `user` table, remember to run the Better Auth CLI to migrate your database:

```bash
npx @better-auth/cli generate
# or
bunx @better-auth/cli generate
```

## 2. Client Setup

Add the `gdprClientPlugin` to your frontend client configuration.

```typescript
// client/auth.ts
import { createAuthClient } from "better-auth/react"; // or /client, /vue, /svelte
import { gdprClientPlugin } from "better-auth-gdpr/client";

export const authClient = createAuthClient({
  baseURL: "http://localhost:3000",
  plugins: [
    gdprClientPlugin(),
    // ... other client plugins
  ],
});
```

## 3. Usage in your Frontend

Using the plugin is incredibly simple. Right before you call **any** sign-up method, use `authClient.gdpr.setConsent()` to load the user's choices into memory. The plugin will automatically attach them to the next sign-up request!

```typescript
import { authClient } from "./auth";

async function handleSignUp(email, password) {
  // 1. Prepare the consents based on your UI checkboxes
  authClient.gdpr.setConsent({
    termsOfService: true,
    privacyPolicy: true,
    newsletter: false,
    isOver18: true,
  });

  // 2. Call the sign-up method (works with email, opaque, etc.)
  // The plugin intercepts this call and securely injects the consents!
  const { data, error } = await authClient.signUp.opaque({
    email,
    password,
    name: "John Doe",
  });

  // 3. Optional but RECOMMENDED: Clear the memory after the attempt
  // This prevents old consents from leaking into future requests if the user retries
  authClient.gdpr.clearConsent();

  if (error) {
    // If a required consent is missing, the server will block it and return a 400 APIError
    console.error("Sign up failed:", error.message);
    return;
  }

  console.log("User created! Consents saved:", data.user.privacyPolicy);
}
```

## Features

- **Protocol Agnostic:** Works perfectly with standard Email/Password, OPAQUE, Passkeys, and OAuth.
- **No CORS Configuration Needed:** Unlike header-based workarounds, this plugin injects data directly into the request body, avoiding annoying preflight CORS issues.
- **Fully Typed:** Thanks to Better Auth's inference engine, `data.user.newsletter` will be automatically typed as a `boolean` in your frontend code.

## License

MIT