# How the @ferdiunal/refine-shadcn-auth Package Integrates with better-auth

> Discover how refineshadcn auth integrates with better-auth using a three-layer architecture. Learn how it maps authentication methods to API calls for seamless integration.

- Repository: [Ferdi ÜNAL/refine-shadcn](https://github.com/ferdiunal/refine-shadcn)
- Tags: deep-dive
- Published: 2026-03-01

---

**The @ferdiunal/refine-shadcn-auth package bridges Refine and better-auth through a three-layer architecture that re-exports the raw better-auth client, wraps HTTP endpoints in an AuthClient class, and implements Refine's AuthProvider contract to map authentication lifecycle methods to better-auth API calls.**

The `@ferdiunal/refine-shadcn-auth` package provides a seamless integration between the Refine React framework and the better-auth authentication library. This integration allows developers to use better-auth as a drop-in authentication backend while maintaining full access to the underlying library's capabilities. According to the ferdiunal/refine-shadcn source code, the package achieves this through a layered architecture that balances convenience with flexibility.

## Three-Layer Integration Architecture

The integration consists of three distinct layers, each serving a specific purpose in connecting Refine's authentication lifecycle with better-auth's API.

### Export Layer: Direct better-auth Access

The foundation of the integration begins in [`src/index.ts`](https://github.com/ferdiunal/refine-shadcn/blob/main/src/index.ts) (line 7), where the package re-exports the raw `betterAuth` client from the better-auth library. This export ensures that developers retain full access to better-auth's server-side utilities, such as session handling and email verification, without needing to install better-auth separately.

```typescript
// packages/auth/src/index.ts
export { betterAuth } from "better-auth";

```

By exposing the native client, the package allows advanced use cases—such as custom middleware or server-side hooks—to coexist with the higher-level Refine integration.

### Client Wrapper: HTTP Endpoint Abstraction

The second layer, implemented in [`src/lib/auth-client.ts`](https://github.com/ferdiunal/refine-shadcn/blob/main/src/lib/auth-client.ts) (lines 1-118), provides the **AuthClient** class—a thin wrapper around better-auth's HTTP endpoints. This class handles request building, JSON serialization, and error propagation for all authentication operations.

The `AuthClient` maps methods to specific better-auth endpoints:

- **Login** → POST `/sign-in/email`
- **Register** → POST `/sign-up/email`
- **Logout** → POST `/sign-out`
- **Session Check** → GET `/session`
- **Password Reset** → POST endpoints for forgot and reset operations

The default base URL (`/api/auth`) aligns with the standard better-auth server middleware route pattern, though this is configurable during instantiation.

### Refine Provider: Lifecycle Method Mapping

The top layer, located in [`src/providers/refine-auth-provider.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/src/providers/refine-auth-provider.tsx) (lines 14-334), implements Refine's `AuthProvider` interface through the `createRefineAuthProvider` function. This factory function accepts an optional `AuthClient` instance (defaulting to a new client with standard configuration) and returns an object containing all required Refine authentication methods.

Each Refine lifecycle method delegates to the corresponding `AuthClient` method:

- `login` → `client.login`
- `logout` → `client.logout`
- `check` → `client.getSession`
- `register` → `client.register`
- `forgotPassword` → `client.forgotPassword`

## Error Handling and Response Propagation

The integration includes consistent error handling across all layers. The `AuthClient` catches HTTP errors and formats them into a standardized shape compatible with Refine's error handling expectations. When the provider encounters HTTP 401 or 403 responses, it optionally triggers automatic logout and redirect flows, maintaining security boundaries within the Refine application lifecycle.

The package declares `better-auth` as a direct dependency in [`packages/auth/package.json`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/auth/package.json), guaranteeing compatible versions without requiring manual peer dependency management.

## Implementation Examples

### Basic Refine Setup

To configure Refine with the built-in provider, instantiate the auth provider and pass it to the Refine component:

```tsx
import { Refine } from "@refinedev/core";
import { createRefineAuthProvider } from "@ferdiunal/refine-shadcn-auth";

const authProvider = createRefineAuthProvider(); // uses default AuthClient

function App() {
  return (
    <Refine
      authProvider={authProvider}
      /* other Refine options … */
    />
  );
}

```

### Direct better-auth Access

For server-side operations or advanced customization, import the re-exported `betterAuth` client directly:

```tsx
import { betterAuth } from "@ferdiunal/refine-shadcn-auth";

// Example: server-side session check in a Next.js API route
export async function GET() {
  const session = await betterAuth.getSession();
  return new Response(JSON.stringify(session), { status: 200 });
}

```

### Custom AuthClient Configuration

When your better-auth server uses a non-standard base URL, provide a custom `AuthClient`:

```tsx
import { createRefineAuthProvider, AuthClient } from "@ferdiunal/refine-shadcn-auth";

const customClient = new AuthClient({ baseURL: "/custom/auth" });
const authProvider = createRefineAuthProvider({ client: customClient });

```

### Component-Level better-auth Utilities

Access better-auth methods directly within React components for features beyond the standard Refine auth flow:

```tsx
import { betterAuth } from "@ferdiunal/refine-shadcn-auth";
import { useState, useEffect } from "react";

function Avatar() {
  const [url, setUrl] = useState<string>("");

  useEffect(() => {
    async function fetchAvatar() {
      const user = await betterAuth.getUser();
      setUrl(user?.avatar ?? "/default-avatar.png");
    }
    fetchAvatar();
  }, []);

  return <img src={url} alt="User avatar" />;
}

```

## Summary

- **Three-layer architecture**: The package exposes better-auth through export, wrapper, and provider layers in [`src/index.ts`](https://github.com/ferdiunal/refine-shadcn/blob/main/src/index.ts), [`src/lib/auth-client.ts`](https://github.com/ferdiunal/refine-shadcn/blob/main/src/lib/auth-client.ts), and [`src/providers/refine-auth-provider.tsx`](https://github.com/ferdiunal/refine-shadcn/blob/main/src/providers/refine-auth-provider.tsx), enabling both simple integration and advanced customization.
- **Direct exports**: Re-exporting `betterAuth` from the entry point allows server-side and advanced client use cases without separate better-auth installation.
- **HTTP abstraction**: The `AuthClient` class standardizes communication with better-auth endpoints like `/sign-in/email` and `/session`, handling JSON bodies and credentials.
- **Refine compatibility**: `createRefineAuthProvider` maps Refine's required methods (`login`, `logout`, `check`, `register`) to better-auth API calls, treating better-auth as a drop-in backend.
- **Configurable defaults**: While defaulting to `/api/auth`, the `AuthClient` accepts custom base URLs and can be injected into the provider factory for flexible deployment scenarios.

## Frequently Asked Questions

### How do I configure a custom base URL for better-auth endpoints?

Pass a custom `AuthClient` instance to `createRefineAuthProvider` with your specific `baseURL`. By default, the client uses `/api/auth`, but you can override this when instantiating the client: `new AuthClient({ baseURL: "/custom/auth" })`. This is useful when your better-auth server middleware runs on a non-standard route.

### Can I use better-auth methods not exposed by the Refine provider?

Yes. The package re-exports the raw `betterAuth` client from [`src/index.ts`](https://github.com/ferdiunal/refine-shadcn/blob/main/src/index.ts), allowing direct access to all better-auth utilities. Import `betterAuth` from `@ferdiunal/refine-shadcn-auth` and use it for server-side logic, custom hooks, or features outside Refine's standard auth lifecycle, such as `betterAuth.getUser()` or `betterAuth.getSession()`.

### What happens when the auth provider receives a 401 or 403 response?

The `createRefineAuthProvider` implementation catches HTTP 401 and 403 errors in its request helper and formats them into Refine's `AuthError` shape. Depending on your Refine configuration, these errors can trigger automatic logout and redirect flows to protect authenticated routes from unauthorized access.

### Is better-auth installed as a dependency or peer dependency?

The package lists `better-auth` as a direct dependency in [`packages/auth/package.json`](https://github.com/ferdiunal/refine-shadcn/blob/main/packages/auth/package.json), ensuring compatible versions are installed automatically. You do not need to add better-auth separately to your project dependencies to use the integration, though you may choose to do so for direct imports outside the package's scope.