Better Auth Integration

Block disposable emails at the auth layer using Better Auth's databaseHooks. Users with throwaway emails are rejected before they ever reach your database.

What is Better Auth?

Better Auth is a modern authentication library for TypeScript. If you use it for signups, this integration blocks disposable emails automatically.

Using databaseHooks

The databaseHooks.user.create.before hook runs before a user is inserted into the database. Return false to reject the signup.

lib/auth.tstypescript
import { betterAuth } from 'better-auth';
import { isDisposable } from '@isdisposable/js';

export const auth = betterAuth({
  // ... your config

  databaseHooks: {
    user: {
      create: {
        before: async (user) => {
          if (isDisposable(user.email)) {
            return false; // Block signup
          }
          return user; // Allow signup
        },
      },
    },
  },
});

Instant, offline

This uses the free package — no API key needed, no network calls. The check happens in under 1ms.

With Pro API (risk scoring)

For stricter protection with real-time DNS checks and risk scoring:

lib/auth.tstypescript
import { betterAuth } from 'better-auth';
import { createIsDisposable } from '@isdisposable/js';

const checker = createIsDisposable({
  apiKey: process.env.ISDISPOSABLE_API_KEY!,
});

export const auth = betterAuth({
  // ... your config

  databaseHooks: {
    user: {
      create: {
        before: async (user) => {
          const result = await checker.check(user.email);

          // Block if score is 70 or higher
          if (result.score >= 70) {
            return false;
          }

          return user;
        },
      },
    },
  },
});

Tune your threshold

score ≥ 50 — blocks most disposable emails (default).
score ≥ 70 — stricter, fewer false positives.
score ≥ 90 — only blocks emails confirmed in the blocklist.

Custom error messages

To show a helpful error message on the client side, throw an APIError:

lib/auth.tstypescript
import { betterAuth } from 'better-auth';
import { APIError } from 'better-auth/api';
import { isDisposable } from '@isdisposable/js';

export const auth = betterAuth({
  databaseHooks: {
    user: {
      create: {
        before: async (user) => {
          if (isDisposable(user.email)) {
            throw new APIError('BAD_REQUEST', {
              message: 'Please use a permanent email address. Disposable emails are not allowed.',
            });
          }
          return user;
        },
      },
    },
  },
});

Log-only mode

Want to monitor without blocking? Log disposable signups instead:

lib/auth.tstypescript
databaseHooks: {
  user: {
    create: {
      before: async (user) => {
        if (isDisposable(user.email)) {
          console.warn(`[isDisposable] Suspicious signup: ${user.email.split('@')[1]}`);
          // Allow the signup but flag it
        }
        return user;
      },
    },
  },
}
This logs the domain only (not the full email) for privacy. You can review the logs and decide whether to start blocking.