# Authentication (/docs/plugins/authentication)





The auth plugin wraps [Better Auth](https://better-auth.com) to provide user login, session management, and admin-only user creation. It's a backend + frontend package.

## Installation [#installation]

<Tabs items="['pnpm', 'npm', 'yarn', 'bun']">
  <Tab value="pnpm">
    ```bash
    pnpm add @flowlib/user-auth
    ```
  </Tab>

  <Tab value="npm">
    ```bash
    npm install @flowlib/user-auth
    ```
  </Tab>

  <Tab value="yarn">
    ```bash
    yarn add @flowlib/user-auth
    ```
  </Tab>

  <Tab value="bun">
    ```bash
    bun add @flowlib/user-auth
    ```
  </Tab>
</Tabs>

## Backend setup [#backend-setup]

The simplest setup lets the plugin manage Better Auth internally — no separate `auth.ts` file needed:

```ts title="flowlib.config.ts"
import { defineConfig } from '@flowlib/core';
import { auth } from '@flowlib/user-auth';

export const flowlibConfig = defineConfig({
  database: { type: 'sqlite', connectionString: 'file:./dev.db' },
  plugins: [
    auth({
      betterAuthOptions: {
        secret: process.env.BETTER_AUTH_SECRET,
      },
      globalAdmins: [{ email: 'admin@example.com', pw: 'changeme', name: 'Admin' }],
    }),
  ],
});
```

For full control, create your own Better Auth instance and pass it in:

```ts title="flowlib.config.ts"
import { betterAuth } from 'better-auth';
import { auth } from '@flowlib/user-auth';

const myAuth = betterAuth({
  /* full Better Auth config */
});

export const flowlibConfig = defineConfig({
  // ...
  plugins: [auth({ auth: myAuth })],
});
```

The `globalAdmins` array seeds admin users on startup. These are the only users that can log in initially — sign-up is disabled in the UI. Subsequent users are created by admins through the user management interface.

After adding the plugin, regenerate and apply the schema:

```bash
npx flowlib-cli generate
npx flowlib-cli migrate --push
```

### Options [#options]

| Option              | Type                                 | Required | Default             | Description                                                                                                    |
| ------------------- | ------------------------------------ | -------- | ------------------- | -------------------------------------------------------------------------------------------------------------- |
| `auth`              | `BetterAuthInstance`                 | No       | —                   | Your own Better Auth instance. If omitted, one is created internally.                                          |
| `betterAuthOptions` | `BetterAuthPassthroughOptions`       | No       | —                   | Options passed to the internal Better Auth instance (ignored when `auth` is provided).                         |
| `globalAdmins`      | `BetterAuthGlobalAdmin[]`            | No       | `[]`                | Admin accounts to seed on startup.                                                                             |
| `database`          | `unknown`                            | No       | —                   | Database for the internal Better Auth instance. Uses Flowlib's DB when omitted.                                |
| `baseURL`           | `string`                             | No       | auto-detected       | Base URL for auth server (cookies, CSRF). Falls back to `BETTER_AUTH_URL` env var.                             |
| `trustedOrigins`    | `string[] \| (req) => string[]`      | No       | localhost + baseURL | Origins trusted for CORS / cookie sharing.                                                                     |
| `publicPaths`       | `string[]`                           | No       | `[]`                | Paths accessible without a valid session (auth proxy routes are always public).                                |
| `mapUser`           | `(user, session) => FlowlibIdentity` | No       | default mapping     | Custom function to map Better Auth users to Flowlib identities.                                                |
| `mapRole`           | `(role) => FlowlibRole`              | No       | default mapping     | Custom function to map Better Auth role strings to Flowlib roles.                                              |
| `apiKey`            | `boolean \| ApiKeyPluginOptions`     | No       | `false`             | Enable the [Better Auth API Key plugin](https://better-auth.com/docs/plugins/api-key) for programmatic access. |
| `frontend`          | `unknown`                            | No       | —                   | Deprecated. The auth plugin registers its UI automatically.                                                    |

## What it does [#what-it-does]

**Backend:**

* `onRequest` hook resolves the session from cookies on every API request
* `onAuthorize` hook enforces that the user is logged in
* Endpoints for sign-in, sign-out, session management, and user CRUD (proxied to Better Auth)
* Admin user seeding on startup from `globalAdmins`

**Frontend:**

* `AuthProvider` — React context providing session state
* `AuthGate` — renders children only when authenticated, shows sign-in page otherwise
* `SignInPage` — pre-built sign-in form
* `UserButton` — avatar with sign-out menu
* `UserManagement` — admin panel for creating/managing users
* `ProfilePage` — user profile page
* `ApiKeysDialog` — API key management (requires `apiKey` option enabled)
* `SidebarUserMenu` — user menu component for the sidebar
* `authFrontend` — deprecated. Auth UI is now registered automatically via the plugin's `appShell`.

## Frontend integration [#frontend-integration]

No extra wrapper component is needed. Pass the `auth()` plugin in `flowlib.config.ts` — `<Flowlib>` reads the config and automatically wraps itself with an auth gate:

```tsx title="app/flowlib/[[...slug]]/page.tsx"
'use client';

import dynamic from 'next/dynamic';
import '@flowlib/ui/styles';
import config from '../../flowlib.config'; // contains plugins: [auth(...), rbac()]

const Flowlib = dynamic(() => import('@flowlib/ui').then((m) => ({ default: m.Flowlib })), {
  ssr: false,
});

export default function FlowlibPage() {
  return <Flowlib config={config} />;
}
```

The OAuth callback route is handled internally at `<frontendPath>/oauth/callback`. You do not need a separate `OAuth2CallbackHandler` route.

For non-Next.js frontends (e.g. Vite + React), import the shared config and pass it the same way:

```tsx title="src/App.tsx"
import { Flowlib } from '@flowlib/ui';
import '@flowlib/ui/styles';
import { flowlibConfig } from '../flowlib.config';

export default function App() {
  return <Flowlib config={flowlibConfig} />;
}
```

## Environment variables [#environment-variables]

| Variable                 | Required | Description                          |
| ------------------------ | -------- | ------------------------------------ |
| `BETTER_AUTH_SECRET`     | Yes      | Session encryption secret            |
| `FLOWLIB_ADMIN_EMAIL`    | No       | Alternative to `globalAdmins` config |
| `FLOWLIB_ADMIN_PASSWORD` | No       | Alternative to `globalAdmins` config |
