Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/elysiajs/documentation/llms.txt

Use this file to discover all available pages before exploring further.

Better Auth is a framework-agnostic authentication and authorization library for TypeScript. It provides a comprehensive feature set out of the box and a plugin ecosystem for advanced use cases. Because Better Auth exposes a standard handler function, you can mount it directly into Elysia. We recommend completing the Better Auth basic setup before following this guide.

Basic setup

Configure your Better Auth instance:
// auth.ts
import { betterAuth } from 'better-auth'
import { Pool } from 'pg'

export const auth = betterAuth({
  database: new Pool()
})

Mounting the handler

Use Elysia’s mount API to attach the Better Auth handler to your app:
// index.ts
import { Elysia } from 'elysia'
import { auth } from './auth'

const app = new Elysia()
  .mount(auth.handler)
  .listen(3000)
Better Auth is now accessible at http://localhost:3000/api/auth.

Custom path prefix

You can mount under a custom path to avoid redundant URL segments:
// index.ts
import { Elysia } from 'elysia'
import { auth } from './auth'

const app = new Elysia()
  .mount('/auth', auth.handler)
  .listen(3000)
Then adjust basePath in your Better Auth config to remove the duplicate /api/auth segment:
export const auth = betterAuth({
  basePath: '/api'
})
Better Auth is now accessible at http://localhost:3000/auth/api.
Better Auth does not support an empty string or / as basePath.

Session macro

Use an Elysia macro with resolve to inject user and session into route context automatically:
import { Elysia } from 'elysia'
import { auth } from './auth'

const betterAuth = new Elysia({ name: 'better-auth' })
  .mount(auth.handler)
  .macro({
    auth: {
      async resolve({ status, request: { headers } }) {
        const session = await auth.api.getSession({ headers })
        if (!session) return status(401)
        return {
          user: session.user,
          session: session.session
        }
      }
    }
  })

const app = new Elysia()
  .use(betterAuth)
  .get('/user', ({ user }) => user, {
    auth: true
  })
  .listen(3000)

CORS

Configure CORS using the @elysia/cors plugin:
import { Elysia } from 'elysia'
import { cors } from '@elysia/cors'
import { auth } from './auth'

const app = new Elysia()
  .use(
    cors({
      origin: 'http://localhost:3001',
      methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
      credentials: true,
      allowedHeaders: ['Content-Type', 'Authorization']
    })
  )
  .mount(auth.handler)
  .listen(3000)

OpenAPI integration

Better Auth supports OpenAPI via its plugin system. To include Better Auth routes in your @elysia/openapi documentation:
1

Add the openAPI plugin to your Better Auth instance

// auth.ts
import { betterAuth } from 'better-auth'
import { openAPI } from 'better-auth/plugins'
import { Pool } from 'pg'

export const auth = betterAuth({
  database: new Pool(),
  plugins: [openAPI()]
})
2

Create a helper to extract the OpenAPI paths

// auth.ts (continued)
let _schema: ReturnType<typeof auth.api.generateOpenAPISchema>
const getSchema = async () => (_schema ??= auth.api.generateOpenAPISchema())

export const OpenAPI = {
  getPaths: (prefix = '/auth/api') =>
    getSchema().then(({ paths }) => {
      const reference: typeof paths = Object.create(null)
      for (const path of Object.keys(paths)) {
        const key = prefix + path
        reference[key] = paths[path]
        for (const method of Object.keys(paths[path])) {
          const operation = (reference[key] as any)[method]
          operation.tags = ['Better Auth']
        }
      }
      return reference
    }) as Promise<any>,
  components: getSchema().then(({ components }) => components) as Promise<any>
} as const
3

Pass the extracted schema to @elysia/openapi

import { Elysia } from 'elysia'
import { openapi } from '@elysia/openapi'
import { OpenAPI } from './auth'

const app = new Elysia().use(
  openapi({
    documentation: {
      components: await OpenAPI.components,
      paths: await OpenAPI.getPaths()
    }
  })
)
The openAPI() plugin is required for auth.api.generateOpenAPISchema to be available. Without it you will get a TypeScript error: Property 'generateOpenAPISchema' does not exist.

Build docs developers (and LLMs) love