Block disposable email signups in WorkOS AuthKit
Hook the `user.created` webhook from WorkOS. Verify the disposable status, then delete the user if needed. AuthKit doesn't expose a synchronous pre-creation hook, so this is the supported pattern.
The code
// app/api/webhooks/workos/route.ts
import { WorkOS } from '@workos-inc/node';
const workos = new WorkOS(process.env.WORKOS_API_KEY!);
async function isDisposable(email: string) {
const r = await fetch(
`https://api.checkdisposable.email/v1/check?email=${encodeURIComponent(email)}`,
{ headers: { Authorization: `Bearer ${process.env.CDE_KEY!}` } }
);
if (!r.ok) return false;
return (await r.json()).is_disposable === true;
}
export async function POST(req: Request) {
const sigHeader = req.headers.get('workos-signature') ?? '';
const payload = await req.text();
const event = await workos.webhooks.constructEvent({
payload: JSON.parse(payload),
sigHeader,
secret: process.env.WORKOS_WEBHOOK_SECRET!,
});
if (event.event === 'user.created') {
const email = (event.data as any).email;
if (email && (await isDisposable(email))) {
await workos.userManagement.deleteUser((event.data as any).id);
}
}
return new Response('ok');
}Notes
- Configure webhook
- WorkOS Dashboard → Webhooks → +endpoint → subscribe to `user.created`. Copy the signing secret into `WORKOS_WEBHOOK_SECRET`.
- Pair with client-side check
- For better UX, also call CheckDisposable Email client-side before showing the AuthKit signup form. The webhook is the backstop; the client check stops most signups before WorkOS even sees them.
- Enterprise SSO
- For SSO via SAML/OIDC, the user.created webhook fires the same way. Same code handles both AuthKit-direct and SSO-federated signups.
Get a free API key
500 checks/month, no credit card. No credit card. 30 seconds.
Sign up free →