Skip to main content
Biovity uses Better Auth for authentication with custom user fields and email/password provider.

Base configuration

The authentication system is configured in lib/auth.ts (server) and lib/auth-client.ts (client).

Server configuration

lib/auth.ts
import { betterAuth } from "better-auth"
import { pool } from "@/lib/db"

export const auth = betterAuth({
  database: pool,
  rateLimit: {
    enabled: true,
    window: 60, // 1 minute
    max: 10, // 10 requests per minute per IP
  },
  emailAndPassword: {
    enabled: true,
  },
  // ... additional configuration
})

Client configuration

lib/auth-client.ts
import { createAuthClient } from "better-auth/react"
import { inferAdditionalFields } from "better-auth/client/plugins"

export const authClient = createAuthClient({
  baseURL: process.env.NEXT_PUBLIC_APP_URL || "http://localhost:3000",
  plugins: [
    inferAdditionalFields({
      user: {
        type: { type: "string", required: true },
        profession: { type: "string", required: true },
        avatar: { type: "string", required: false },
        isActive: { type: "boolean", required: false },
        organizationId: { type: "string", required: false },
      },
    }),
  ],
})

API endpoints

All authentication endpoints are served through the Next.js API route at /api/auth/*.
app/api/auth/[...all]/route.ts
import { toNextJsHandler } from "better-auth/next-js"
import { auth } from "@/lib/auth"

export const { POST, GET } = toNextJsHandler(auth)

Available endpoints

EndpointMethodDescription
/api/auth/sign-in/emailPOSTEmail/password login
/api/auth/sign-up/emailPOSTEmail/password registration
/api/auth/sign-outPOSTEnd user session
/api/auth/sessionGETGet current session

Security features

Rate limiting

Rate limiting is enabled to prevent brute force attacks:
window
number
default:"60"
Time window in seconds for rate limit calculation
max
number
default:"10"
Maximum requests allowed per IP address within the window

Session management

Sessions are configured with the following parameters:
expiresIn
number
default:"604800"
Session expiration time in seconds (7 days)
updateAge
number
default:"86400"
Session refresh interval in seconds (1 day). Sessions automatically refresh after 1 day of activity.
Enable cookie-based session caching
Cookie cache duration in seconds (5 minutes)

Secure cookies

Cookies are configured to use secure flags in production:
advanced: {
  useSecureCookies: process.env.NODE_ENV === "production",
}

Custom user fields

Biovity extends the default Better Auth user model with additional fields:
type
string
required
User type: employee or organization
profession
string
required
User’s professional designation or field
avatar
string
URL to user’s profile avatar image
isActive
boolean
Account activation status
organizationId
string
Associated organization ID for employee users
verificationToken
string
Email verification token (internal use only)

Database schema

Better Auth uses custom field mappings for PostgreSQL:

User table

user: {
  modelName: "user",
  fields: {
    email: "email",
    name: "name",
    emailVerified: "isEmailVerified",
    createdAt: "createdAt",
    updatedAt: "updatedAt",
  },
}

Session table

session: {
  modelName: "session",
  fields: {
    userId: "user_id",
    expiresAt: "expires_at",
    token: "token",
    ipAddress: "ip_address",
    userAgent: "user_agent",
    createdAt: "created_at",
    updatedAt: "updated_at",
  },
}

Logging

Logging level is environment-dependent:
logger: {
  level: process.env.NODE_ENV === "production" ? "error" : "debug",
}

Build docs developers (and LLMs) love