A before-create hook on the user table.
Runs in a database hook. Every name is checked with context: "username" and the teen policy; change the policy to suit the audience. Replace the key.
// auth.ts: Better Auth database hook
import { betterAuth } from 'better-auth';
import { Unprofane } from '@unprofane/sdk';
const unprofane = new Unprofane(process.env.UNPROFANE_API_KEY!);
/** Returns the reason a username cannot be shown, or null when it can. */
export async function usernameProblem(username: string): Promise<string | null> {
const r = await unprofane.check({ text: username, context: 'username', policy: 'teen' });
if (r.allowed) return null;
return r.matches[0]?.category === 'reserved'
? 'That name is reserved.'
: 'Pick a different username.';
}
export const auth = betterAuth({
databaseHooks: {
user: {
create: {
before: async (user) => {
const problem = await usernameProblem(user.name);
if (problem) throw new Error(problem);
return { data: user };
},
},
},
},
});Throwing in the hook cancels the create and returns the message to the client.
What the response holds, and how to read a reserved name apart from a profane one, is in the API reference. The other recipes are on the username page.