# @neondatabase/auth

> TypeScript SDK for Neon Auth - authentication for PostgreSQL with multiple adapter support

Latest version **0.7.0-beta** (published 2026-10-21) · Apache-2.0 license · 0 weekly downloads

## Install

```sh
npm install @neondatabase/auth
pnpm add @neondatabase/auth
yarn add @neondatabase/auth
bun add @neondatabase/auth
```

Provides the command `neon-auth-codemod`.

## Health

**Score 70/100 (B)** — status: active.

Positive: has types; esm support; no vulnerabilities; recently updated; high maintenance score; high quality score.

Warnings: low downloads; pre 1.0.

## Facts

| | |
|---|---|
| Version | 0.7.0-beta |
| Published | 2026-10-21 |
| First published | 2025-12-07 |
| Weekly downloads | 0 |
| License | Apache-2.0 |
| TypeScript types | bundled |
| Module format | ESM + CommonJS |
| Dependencies | 10 |
| Unpacked size | 468 KB |
| Known vulnerabilities | 0 (+4 in 2 direct dependencies) |
| Install scripts | no |
| GitHub stars | 19 |
| Author | Pedro Figueiredo |
| Maintainers | jawj, amitdahan, pffigueiredo, shridharneon, atilaz, neonteam |
| Keywords | neon, neondb, postgresql, postgres, authentication, auth, typescript, sdk, better-auth, supabase, react, nextjs |

## Links

- npm: https://www.npmjs.com/package/@neondatabase/auth
- Repository: https://github.com/neondatabase/neon-js
- Homepage: https://github.com/neondatabase/neon-js/tree/main/packages/auth#readme
- Issues: https://github.com/neondatabase/neon-js/issues
- Funding: https://neon.tech
- npm.io page: https://npm.io/package/@neondatabase/auth

## Dependencies (10)

- [zod](https://npm.io/package/zod.md) 4.5.4
- [jose](https://npm.io/package/jose.md) 6.2.5
- [better-auth](https://npm.io/package/better-auth.md) 1.7.6
- [better-call](https://npm.io/package/better-call.md) 1.4.0
- [@better-auth/core](https://npm.io/package/@better-auth/core.md) 1.7.6
- [@supabase/auth-js](https://npm.io/package/@supabase/auth-js.md) 2.79.0
- [@better-auth/utils](https://npm.io/package/@better-auth/utils.md) 0.4.2
- [@better-fetch/fetch](https://npm.io/package/@better-fetch/fetch.md) 1.3.2
- [@neondatabase/auth-ui](https://npm.io/package/@neondatabase/auth-ui.md) 0.4.0-beta
- [@better-auth/oauth-provider](https://npm.io/package/@better-auth/oauth-provider.md) 1.7.6

## Alternatives

- [@pothos/plugin-authz](https://npm.io/package/@pothos/plugin-authz.md) — 12.4K weekly downloads
- [@bounded-sh/client](https://npm.io/package/@bounded-sh/client.md) — 3.2K weekly downloads
- [@luigi-project/plugin-auth-oauth2](https://npm.io/package/@luigi-project/plugin-auth-oauth2.md) — 2.3K weekly downloads
- [@nocobase/plugin-verification](https://npm.io/package/@nocobase/plugin-verification.md) — 2.0K weekly downloads
- [escher-request](https://npm.io/package/escher-request.md) — 545 weekly downloads

## Recent versions

- 0.7.0-beta (latest) — 2026-10-21
- 0.6.0-beta — 2026-10-12
- 0.5.0-beta — 2026-08-11
- 0.4.2-beta — 2026-06-08
- 0.4.1-beta — 2026-05-10
- 0.4.0-beta — 2026-05-08
- 0.3.0-beta — 2026-04-29
- 0.2.0-beta.1 — 2026-01-29
- 0.1.0-beta.21 — 2026-01-14
- 0.1.0-beta.20 — 2025-12-23
- 0.1.0-beta.19 — 2025-12-21
- 0.1.0-beta.18 — 2025-12-18
- 0.1.0-beta.17 — 2025-12-18
- 0.1.0-beta.16 — 2025-12-17
- 0.1.0-beta.15 — 2025-12-12
- … 14 more at https://npm.io/package/@neondatabase/auth/versions

## README

# @neondatabase/auth

[![npm version](https://img.shields.io/npm/v/@neondatabase/auth.svg)](https://www.npmjs.com/package/@neondatabase/auth)
[![npm downloads](https://img.shields.io/npm/dm/@neondatabase/auth.svg)](https://www.npmjs.com/package/@neondatabase/auth)
[![TypeScript](https://img.shields.io/badge/TypeScript-5.0%2B-blue.svg)](https://www.typescriptlang.org/)
[![License](https://img.shields.io/npm/l/@neondatabase/auth.svg)](https://github.com/neondatabase/neon-js/blob/main/LICENSE)

Authentication adapters for Neon Auth, supporting multiple auth providers.

## Overview

`@neondatabase/auth` provides authentication for applications using Neon Auth. By default, it uses the Better Auth API, with optional adapters for different API styles:

- **Default** - Better Auth API (`signIn.email`, `signUp.email`, etc.)
- **SupabaseAuthAdapter** - Supabase-compatible API for migrations (`signInWithPassword`, `signUp`, etc.)
- **BetterAuthReactAdapter** - Better Auth with React hooks (`useSession`)

This package is designed to work seamlessly with Neon's authentication infrastructure while providing:

- **Simple default API** - Works out of the box with Better Auth patterns
- **Optional adapters** - Switch API styles for migrations or preferences
- **Anonymous access** - Optional RLS-based data access for unauthenticated users
- **Performance optimizations** - Session caching and request deduplication
- **TypeScript support** - Fully typed with strict type checking

## Why @neondatabase/auth?

### vs. better-auth/client

`@neondatabase/auth` is a wrapper around Better Auth that provides:

**API Flexibility:**
- Multiple adapters (Supabase-compatible, React hooks, vanilla)
- Restricted options to match Neon Auth capabilities

**Neon Auth Integration:**
- Automatic `token_verifier` on OAuth callback
- Pre-configured plugins for Neon Auth
- Automatic JWT extraction from sessions
- Popup-based OAuth flow for iframes

**Built-in Enhancements:**
- Session caching (60s TTL)
- Request deduplication
- Event system
- Cross-tab sync
- Token refresh detection

If you're not using Neon Auth, you should probably use `better-auth/client` directly for more flexibility.

## Installation

```bash
npm install @neondatabase/auth
# or
bun add @neondatabase/auth
```

## Usage

### Basic Usage (Default)

The `createAuthClient` factory function creates an auth client. By default, it uses the Better Auth API:

```typescript
import { createAuthClient } from '@neondatabase/auth';

const auth = createAuthClient('https://your-auth-server.com');

// Sign up
await auth.signUp.email({
  email: 'user@example.com',
  password: 'secure-password',
  name: 'John Doe',
});

// Sign in
await auth.signIn.email({
  email: 'user@example.com',
  password: 'secure-password',
});

// Get session
const session = await auth.getSession();

// Sign out
await auth.signOut();
```

### OAuth Authentication

```typescript
import { createAuthClient } from '@neondatabase/auth';

const auth = createAuthClient('https://your-auth-server.com');

await auth.signIn.social({
  provider: 'google',
  callbackURL: '/dashboard',
});
```

## Using Adapters

You can optionally specify an adapter to change the API style. This is useful for migrations or if you prefer a different API.

### SupabaseAuthAdapter - Supabase-compatible API

Use this adapter if you're migrating from Supabase or prefer the Supabase API style:

```typescript
import { createAuthClient, SupabaseAuthAdapter } from '@neondatabase/auth';

const auth = createAuthClient('https://your-auth-server.com', {
  adapter: SupabaseAuthAdapter(),
});

// Supabase-compatible methods
await auth.signUp({
  email: 'user@example.com',
  password: 'secure-password',
  options: {
    data: { name: 'John Doe' },
  },
});

await auth.signInWithPassword({
  email: 'user@example.com',
  password: 'secure-password',
});

const { data: session } = await auth.getSession();
await auth.signOut();

// OAuth with Supabase-style API
await auth.signInWithOAuth({
  provider: 'google',
  options: {
    redirectTo: '/dashboard',
  },
});
```

### BetterAuthReactAdapter - React Hooks Support

Use this adapter in React applications to get access to hooks like `useSession`:

```typescript
import { createAuthClient } from '@neondatabase/auth';
import { BetterAuthReactAdapter } from '@neondatabase/auth/react/adapters';

const auth = createAuthClient('https://your-auth-server.com', {
  adapter: BetterAuthReactAdapter(),
});

// Same API as default
await auth.signIn.email({
  email: 'user@example.com',
  password: 'secure-password',
});

// Plus React hooks
function MyComponent() {
  const session = auth.useSession();

  if (session.isPending) return <div>Loading...</div>;
  if (!session.data) return <div>Not logged in</div>;

  return <div>Hello, {session.data.user.name}</div>;
}
```

## OAuth provider (MCP)

A Neon Auth project can act as an OAuth 2.1 provider, for example to let MCP clients sign in your users. The provider's login and consent pages are pages of your app, and the client exposes the `oauth2` namespace for them; no configuration is needed:

```typescript
import { createAuthClient } from '@neondatabase/auth';

export const auth = createAuthClient('https://your-auth-server.com');
```

When the page URL carries the signed `sig` and `ba_param` query parameters that the provider appended on redirect, the client adds them as `oauth_query` to every non-GET request, so a sign-in on the login page resumes the authorization. Without those parameters requests are unchanged.

A consent page reads the client from the URL and answers with `oauth2.consent`:

```tsx
'use client';
import { useEffect, useState } from 'react';
import { auth } from '@/lib/auth/client';

export default function ConsentPage() {
  const [scope, setScope] = useState<string | null>(null);
  const [client, setClient] = useState<{ client_name?: string; logo_uri?: string } | null>(null);

  // Read the query in an effect: the page also renders on the server, where `window` is undefined.
  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    setScope(params.get('scope'));
    auth.oauth2
      .publicClient({ query: { client_id: params.get('client_id') ?? '' } })
      .then(({ data }) => setClient(data));
  }, []);

  const answer = (accept: boolean) => auth.oauth2.consent({ accept });

  return (
    <div>
      <p>{client?.client_name ?? 'An application'} wants to access: {scope}</p>
      <button onClick={() => answer(true)}>Allow</button>
      <button onClick={() => answer(false)}>Deny</button>
    </div>
  );
}
```

`oauth2.consent()` navigates the browser itself: it returns `{ redirect: true, url }`, and better-auth's default redirect fetch plugin sets `window.location.href`, so the page does not need to follow it.

The browser client's `oauth2.*` mirrors the full plugin. Neon mounts these endpoints:

| Group | Endpoints | In `createNeonAuth()` | Notes |
| --- | --- | --- | --- |
| Login and consent actions | `consent`, `continue`, `publicClient`, `publicClientPrelogin` | Yes | Drive your login and consent pages. |
| The user's own grants | `getConsent`, `getConsents`, `updateConsent`, `deleteConsent` | Yes | Let a signed-in user review and revoke what they granted. |
| Client management | `create-client`, `get-client`, `get-clients`, `update-client`, `delete-client`, `client/rotate-secret` | No | Neon rejects these for end users with 401; manage clients through the Neon Console or API. |
| OAuth protocol | `authorize`, `token`, `introspect`, `revoke`, `userinfo`, `register` | No | Use client credentials or bearer tokens with form bodies or redirects. Relying parties and MCP servers should use `@neon/oauth`. |
| RP-initiated logout | `end-session`, `end-session/confirm` | No | Browser redirect flow. |

`createNeonAuth()` and `createAuthServer()` expose only the first two groups. A server-side consent example is not documented, because `oauth_query` has to be the signed query the provider redirected with and is only built automatically in the browser.

## Anonymous Access

Enable `allowAnonymous` to let unauthenticated users access data via RLS policies:

```typescript
import { createAuthClient } from '@neondatabase/auth';

const auth = createAuthClient('https://your-auth-server.com', {
  allowAnonymous: true, // Enable anonymous data access
});

// Get token - returns anonymous token if no user session exists
const token = await auth.getJWTToken?.();
```

This is useful when you want to allow read-only public access to certain data while still enforcing RLS policies.

## API Reference

### createAuthClient(url, config?)

Factory function to create an auth client.

**Parameters:**
- `url` - The auth service URL (required)
- `config.adapter` - Optional adapter factory function (e.g., `SupabaseAuthAdapter()`)
- `config.allowAnonymous` - When `true`, returns an anonymous token if no user session exists (default: `false`)

**Returns:** The adapter's public API (varies by adapter type)

### Default API (Better Auth)

- `signIn.email(credentials)` - Sign in with email
- `signIn.social(options)` - Sign in with OAuth
- `signUp.email(credentials)` - Create new user
- `signOut()` - Sign out current user
- `getSession()` - Get current session

### SupabaseAuthAdapter API

Provides a Supabase-compatible API:

- `signUp(credentials)` - Create a new user
- `signInWithPassword(credentials)` - Sign in with email/password
- `signInWithOAuth(options)` - Sign in with OAuth provider
- `signOut()` - Sign out current user
- `getSession()` - Get current session
- `getUser()` - Get current user
- `updateUser(attributes)` - Update user metadata
- `getUserIdentities()` - Get linked OAuth identities
- `linkIdentity(credentials)` - Link OAuth provider
- `unlinkIdentity(identity)` - Unlink OAuth provider
- `resetPasswordForEmail(email, options)` - Send password reset
- `onAuthStateChange(callback)` - Listen to auth state changes

### BetterAuthReactAdapter API

Same as default API, plus:

- `useSession()` - React hook for session state

## Performance Features

### Session Caching

Sessions are cached in memory with intelligent TTL management:
- 60-second default cache TTL
- Automatic expiration based on JWT `exp` claim
- Lazy expiration checking on reads
- Synchronous cache clearing on sign-out

### Request Deduplication

Multiple concurrent `getSession()` calls are automatically deduplicated:
- Single network request for concurrent calls
- 10x faster cold starts (10 concurrent calls: ~2000ms → ~200ms)
- Reduces server load by N-1 for N concurrent calls

## Environment Compatibility

- Node.js 14+
- Browser (all modern browsers)
- Edge Runtime (Vercel, Cloudflare Workers, etc.)
- Bun

## Next.js Integration

For Next.js projects, this package provides built-in integration via `@neondatabase/auth/next`. 
See the [Next.js Setup Guide](./NEXT-JS.md) for comprehensive documentation including:

- Setting up auth server instance with `createNeonAuth()` for handler, middleware and api methods  
- Client-side auth with `createAuthClient()` for client components
- Configuring the `NeonAuthUIProvider` with Email OTP, Social Login, and Organizations
- Creating auth pages (`AuthView`, `AccountView`, `OrganizationView`)
- Importing styles (with or without Tailwind CSS)
- Using `authClient.useSession()` hook in client components

## Server toolkit (for framework adapter authors)

> **Stability: beta.** Minor versions may include breaking changes with migration
> notes in the package CHANGELOG. Pin your peer dependency accordingly.

`@neondatabase/auth/server` exposes the framework-agnostic primitives that the
bundled `@neondatabase/auth/next/server` adapter is built on. Use it to build
adapters for additional server frameworks (Hono, Remix, SolidStart, Express,
Fastify, ...) without forking the package.

```typescript
import {
  createAuthServer,
  handleAuthProxyRequest,
  processAuthMiddleware,
  validateCookieConfig,
  resolveNeonAuthLogging,
  DEFAULT_AUTH_SKIP_ROUTES,
  type RequestContext,
  type NeonAuthConfig,
  type MiddlewareResult,
} from '@neondatabase/auth/server';
```

The toolkit is **Web Standards only** — it consumes `Request`/`Response` and
exposes a small `RequestContext` interface that adapter authors implement for
their framework's cookie/header APIs. The bundled Next.js adapter is the
reference implementation; see [`BUILDING-AN-ADAPTER.md`](./BUILDING-AN-ADAPTER.md)
for a walkthrough.

## UI Components

Pre-built login forms and auth pages live in `@neondatabase/auth-ui`. The
legacy `@neondatabase/auth/react/ui` and `@neondatabase/auth/ui/*` entrypoints
still work for compatibility, but they are deprecated and will be removed in
the next major version.

To migrate existing imports, run:

```bash
npx -p @neondatabase/auth neon-auth-codemod --write <path>
```

### 1. Import CSS

Install the UI package alongside `@neondatabase/auth`:

```bash
npm install @neondatabase/auth-ui
```

**Without Tailwind CSS:**
```typescript
import '@neondatabase/auth-ui/css';
```

**With Tailwind CSS v4:**
```css
@import 'tailwindcss';
@import '@neondatabase/auth-ui/tailwind';
```

### 2. Setup Provider

```typescript
"use client"

import { NeonAuthUIProvider } from "@neondatabase/auth-ui"
import { createAuthClient } from "@neondatabase/auth"
import "@neondatabase/auth-ui/css"

const authClient = createAuthClient('https://your-auth-url.com')

export function AuthProvider({ children }) {
  return (
    <NeonAuthUIProvider authClient={authClient} redirectTo="/dashboard">
      {children}
    </NeonAuthUIProvider>
  )
}
```

### 3. Use Components

**Option A: Full Auth Pages (Recommended)**

Use `AuthView` to render complete auth flows based on the URL path:

```typescript
import { AuthView } from "@neondatabase/auth-ui"

// Renders sign-in, sign-up, forgot-password, etc. based on path
<AuthView path="sign-in" />
```

**Option B: Individual Components**

```typescript
import { SignInForm, UserButton } from "@neondatabase/auth-ui"

<SignInForm />
<UserButton />
```

Available components: `SignInForm`, `SignUpForm`, `UserButton`, `AuthView`, `AccountView`, `OrganizationView`

For Next.js with dynamic routes, see the [Next.js Setup Guide](./NEXT-JS.md).

For full documentation and theming, see [`@neondatabase/auth-ui`](../auth-ui).

## Related Packages

- [`@neondatabase/neon-js`](../neon-js) - Full SDK with database and auth integration
- [`@neondatabase/postgrest-js`](../postgrest-js) - PostgREST client without auth

## Resources

- [Neon Auth Documentation](https://neon.com/docs/neon-auth)
- [Better Auth Documentation](https://www.better-auth.com/docs)

## Support

- [GitHub Issues](https://github.com/neondatabase/neon-js/issues)
- [Neon Community Discord](https://discord.gg/H24eC2UN)

## License

Apache-2.0

---
_Source: https://npm.io/package/@neondatabase/auth · Machine-readable twin of the npm.io package page. Health data is recomputed on every publish._
