Skip to main content
The auth package uses an adapter pattern to integrate with any authentication provider. This page covers how to configure adapters and use TypeScript types.

Auth Adapter

The AuthAdapter type defines the interface your authentication provider must implement:
export type AuthAdapter = {
  signIn: (data: Record<string, any>) => Promise<void>;
  signUp?: (data: Record<string, any>) => Promise<void>;
  signOut?: () => Promise<void>;
  getSession?: () => Promise<Record<string, any> | null>;
};

Required Methods

signIn

Handles user authentication. Receives form data and should authenticate the user.
signIn: async (data: Record<string, any>) => {
  const { email, password } = data;
  await yourAuthProvider.signIn(email, password);
}

Optional Methods

signUp

Handles user registration. If not provided, the RegisterForm component can still be used, but you’ll need to handle registration separately.
signUp: async (data: Record<string, any>) => {
  const { email, password } = data;
  await yourAuthProvider.signUp(email, password);
}

signOut

Handles user sign-out. If not provided, the signOut method from useAuth will be a no-op.
signOut: async () => {
  await yourAuthProvider.signOut();
}

getSession

Retrieves the current user session. Not currently used by the package, but available for future features.
getSession: async () => {
  return await yourAuthProvider.getSession();
}

TypeScript Types

UseAuthOptions

Options for the useAuth hook:
export type UseAuthOptions = {
  adapter?: AuthAdapter;
};
Usage:
import { useAuth } from '@repo/auth';
import type { UseAuthOptions } from '@repo/auth';

const options: UseAuthOptions = {
  adapter: myAuthAdapter,
};

const auth = useAuth(options);

Example Adapters

Better Auth Adapter

import { authClient } from './auth-client';
import type { AuthAdapter } from '@repo/auth';

export const betterAuthAdapter: AuthAdapter = {
  signIn: async (data) => {
    const { email, password } = data;
    await authClient.signIn.email(
      { email, password },
      { onSuccess: () => window.location.href = '/dashboard' }
    );
  },
  signUp: async (data) => {
    const { email, password } = data;
    await authClient.signUp.email(
      { email, password },
      { onSuccess: () => window.location.href = '/dashboard' }
    );
  },
  signOut: async () => {
    await authClient.signOut();
  },
};

NextAuth Adapter

import { signIn, signOut, signUp } from 'next-auth/react';
import type { AuthAdapter } from '@repo/auth';

export const nextAuthAdapter: AuthAdapter = {
  signIn: async (data) => {
    const result = await signIn('credentials', {
      email: data.email,
      password: data.password,
      redirect: false,
    });
    
    if (result?.error) {
      throw new Error(result.error);
    }
  },
  signUp: async (data) => {
    const response = await fetch('/api/auth/register', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data),
    });
    
    if (!response.ok) {
      throw new Error('Registration failed');
    }
  },
  signOut: async () => {
    await signOut({ redirect: false });
  },
};

Supabase Adapter

import { createClient } from '@supabase/supabase-js';
import type { AuthAdapter } from '@repo/auth';

const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_ANON_KEY!);

export const supabaseAdapter: AuthAdapter = {
  signIn: async (data) => {
    const { error } = await supabase.auth.signInWithPassword({
      email: data.email,
      password: data.password,
    });
    
    if (error) throw error;
  },
  signUp: async (data) => {
    const { error } = await supabase.auth.signUp({
      email: data.email,
      password: data.password,
    });
    
    if (error) throw error;
  },
  signOut: async () => {
    const { error } = await supabase.auth.signOut();
    if (error) throw error;
  },
};
Create your adapter in a separate file (e.g., auth-adapter.ts) so you can reuse it across your application.

Enhanced Error Handling

The useAuth hook automatically enhances error messages to be more user-friendly. It converts technical errors into readable messages:
Original ErrorEnhanced Message
CSRF token missingSession expired. Please refresh the page and try again.
Failed to fetchUnable to connect. Please check your internet connection.
Request timeoutRequest timed out. Please try again.
CORS errorConnection blocked. Please contact support.
You can still access the original error message if needed, but users will see the enhanced version.

Environment Variables

While the auth package itself doesn’t require environment variables, your adapter likely will. Common patterns:
# Better Auth
BETTER_AUTH_SECRET=your-secret-key
BETTER_AUTH_URL=http://localhost:3000

# NextAuth
NEXTAUTH_SECRET=your-secret-key
NEXTAUTH_URL=http://localhost:3000

# Supabase
NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key
Always prefix client-side environment variables with NEXT_PUBLIC_ in Next.js applications.

Build docs developers (and LLMs) love