new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

Better Auth · Concepts · all subjects

database/hooks

12 notes, read out of this brain and free to use. Each one was extracted from a source and is re-checked against its exam.

Database hooks lifecycle

Database hooks allow custom logic during lifecycle of core database operations in Better Auth. You can create hooks for user, session, and account models. Two types of hooks exist: before (called before create, update, or delete; can abort operation by returning false or replace payload by returning data object) and after (called after create or update for additional actions).

Database hooks before hook behavior

A before hook is called before an entity is created, updated, or deleted. If it returns false, the operation aborts. If it returns a data object, it replaces the original payload. The hook receives the entity and a context object.

Database hooks after hook behavior

An after hook is called after an entity is created or updated. You can perform additional actions or modifications after the entity has been successfully created or updated.

Example: Database hooks for user creation

```typescript import { betterAuth } from "better-auth"; export const auth = betterAuth({ databaseHooks: { user: { create: { before: async (user, ctx) => { return { data: { ...user, firstName: user.name.split(" ")[0], lastName: user.name.split(" ")[1], }, }; }, after: async (user) => { // Create stripe customer or other actions }, }, }, }, }); ```

Example: Database hooks for preventing user deletion

```typescript import { betterAuth } from "better-auth"; export const auth = betterAuth({ databaseHooks: { user: { delete: { before: async (user, ctx) => { if (user.email.includes("admin")) { return false; // Abort deletion } return true; // Allow deletion }, after: async (user) => { console.log(`User ${user.email} has been deleted`); }, }, }, }, }); ```

Database hooks error handling with APIError

To stop a database hook from proceeding, throw errors using the APIError class imported from 'better-auth/api'. Example: throw new APIError('BAD_REQUEST', { message: 'User must agree to the TOS before signing up.' })

Database hooks context object

The context object (ctx) passed as the second argument to a hook contains useful information. For update hooks, it includes the current session, which you can use to access the logged-in user's details via ctx.context.session.userId.

Access additional OAuth data in hooks with getOAuthState

Additional data passed through the OAuth flow is available in hooks during the OAuth callback through the getOAuthState function. This usually works for /callback/:id paths and the generic OAuth plugin callback path (/oauth2/callback/:providerId).

getOAuthState in after hook example

Example using getOAuthState in an after hook to access additional data: ```ts import { betterAuth } from "better-auth"; import { getOAuthState } from "better-auth/api"; export const auth = betterAuth({ hooks: { after: [ { matcher: () => true, handler: async (ctx) => { if (ctx.path === "/callback/:id") { const additionalData = await getOAuthState<{ referralCode?: string; source?: string; }>(); if (additionalData) { // IMPORTANT: Validate and sanitize the data before using it // This data comes from the client and should not be trusted if (additionalData.referralCode) { const isValidFormat = /^[A-Z0-9]{6}$/.test(additionalData.referralCode); if (isValidFormat) { const referral = await db.referrals.findByCode(additionalData.referralCode); if (referral) { await db.referrals.incrementUsage(referral.id); } } } if (additionalData.source) { await analytics.track("oauth_signin", { source: additionalData.source, userId: ctx.context.session?.user.id, }); } } } }, }, ], }, }); ```

getOAuthState in database hook example

Example using getOAuthState in a database hook: ```ts databaseHooks: { user: { create: { before: async (user, ctx) => { if (ctx.path === "/callback/:id") { const additionalData = await getOAuthState<{ referredFrom?: string }>(); if (additionalData?.referredFrom) { return { data: { referredFrom: additionalData.referredFrom, }, }; } } }, }, }, } ```

Token encryption with databaseHooks

Better Auth does not encrypt tokens by default. To encrypt tokens like accessToken or refreshToken, use databaseHooks with the account.create.before hook to encrypt before saving to the database, and decrypt when retrieving.

Token encryption example with databaseHooks

Example of encrypting tokens in databaseHooks: In the account.create.before hook, check if account.accessToken or account.refreshToken exist, encrypt them using your encrypt function, and return the modified account in the data property of the returned object.

Give your agent this brain