Sigma Auth
Customization

Better Auth Foundation

Sigma Auth is built on top of Better Auth, a modern authentication framework that provides:

  • Type-Safe: Full TypeScript support with type inference
  • Framework Agnostic: Works with any web framework or platform
  • Plugin Architecture: Extensible through custom plugins
  • OAuth 2.0 Compatible: Standard OAuth flows with custom providers

Architecture Overview

Sigma Auth implements a custom Better Auth plugin called sigma that adds Bitcoin authentication support. The architecture consists of:

  1. Client pluginsigmaClient() from @sigma-auth/better-auth-plugin/client, handles OAuth flow initiation and callback handling
  2. Server plugin (in the auth server) — manages Bitcoin signature verification
  3. OAuth bridge — standard OAuth 2.0 authorization code flow

Authentication Flow

Here's how the Bitcoin authentication flow works with Better Auth:

Client Configuration

Install the official Sigma Auth plugin for Better Auth:

bun add @sigma-auth/better-auth-plugin better-auth

Configure the auth client:

lib/auth-client.ts
import { createAuthClient } from 'better-auth/client';
import { sigmaClient } from '@sigma-auth/better-auth-plugin/client';

export const authClient = createAuthClient({
  baseURL: 'https://auth.sigmaidentity.com',
  plugins: [sigmaClient()],
});

// Export signIn and other utilities
export const { signIn } = authClient;

Server-Side Token Exchange (Next.js)

Create a callback route to handle the OAuth code exchange:

app/api/auth/sigma/callback/route.ts
import { createCallbackHandler } from "@sigma-auth/better-auth-plugin/next";

export const POST = createCallbackHandler();

The callback handler:

  • Exchanges the authorization code for tokens
  • Signs the request with your member key
  • Returns user profile with BAP identity data

Usage in Components

Sign In

components/auth-button.tsx
'use client';

import { signIn } from '@/lib/auth-client';

const SIGMA_CLIENT_ID = process.env.NEXT_PUBLIC_SIGMA_CLIENT_ID ?? '';

export function SignInButton() {
  const handleSignIn = () => {
    signIn.sigma({ clientId: SIGMA_CLIENT_ID });
  };

  return (
    <button type="button" onClick={handleSignIn}>
      Sign In with Sigma
    </button>
  );
}

The plugin handles PKCE automatically.

Session Management

components/user-profile.tsx
import { useSession } from '@/lib/auth-client';

export function UserProfile() {
  const { data: session, isPending } = useSession();

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

  return (
    <div>
      <p>Welcome, {session.user.profile?.name || session.user.pubkey}</p>
      <p>Bitcoin Address: {session.user.address}</p>
    </div>
  );
}

OAuth Callback Page

The plugin's authClient.sigma.handleCallback takes the search params, verifies state, exchanges the code via your /api/auth/sigma/callback route, and returns the user and tokens. useSearchParams must be wrapped in <Suspense>.

app/auth/sigma/callback/page.tsx
'use client';

import { useRouter, useSearchParams } from 'next/navigation';
import { Suspense, useEffect, useState } from 'react';
import { authClient } from '@/lib/auth-client';

function CallbackContent() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const [error, setError] = useState('');

  useEffect(() => {
    authClient.sigma
      .handleCallback(searchParams)
      .then((result) => {
        localStorage.setItem(
          'auth_session',
          JSON.stringify({ user: result.user, access_token: result.access_token })
        );
        router.push('/dashboard');
      })
      .catch((err: Error) => setError(err.message));
  }, [searchParams, router]);

  if (error) {
    return <p>Error: {error}</p>;
  }

  return <p>Processing authentication...</p>;
}

export default function CallbackPage() {
  return (
    <Suspense fallback={<p>Loading...</p>}>
      <CallbackContent />
    </Suspense>
  );
}

Benefits of Better Auth

Type Safety

  • Full TypeScript support with automatic type inference
  • Type-safe plugin development
  • No manual type definitions needed

Modern Architecture

  • Plugin-based extensibility
  • React Query integration
  • Optimistic updates

Developer Experience

  • Simple API with powerful features
  • Excellent documentation
  • Active community support

Environment Variables

.env.local
# Required
NEXT_PUBLIC_SIGMA_CLIENT_ID=your-app
SIGMA_MEMBER_PRIVATE_KEY=your-member-wif

# Optional (defaults shown)
NEXT_PUBLIC_SIGMA_AUTH_URL=https://auth.sigmaidentity.com

The SIGMA_MEMBER_PRIVATE_KEY is used to sign token exchange requests. You receive this when you register your OAuth client at auth.sigmaidentity.com/account.

Learn More

For Bitcoin-specific features and implementation details, see our Bitcoin Authentication Guide.

On this page