> ## Documentation Index
> Fetch the complete documentation index at: https://docs.base.org/llms.txt
> Use this file to discover all available pages before exploring further.

# Auth (Sign In With Base)

> Manage user authentication with Privy and Base Account

export const GithubRepoCard = ({title, githubUrl}) => {
  return <a href={githubUrl} target="_blank" rel="noopener noreferrer" className="mb-4 flex items-center rounded-lg bg-zinc-900 p-4 text-white transition-all hover:bg-zinc-800">
      <div className="flex w-full items-center gap-3">
        <svg height="24" width="24" className="flex-shrink-0 dark:fill-white" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg">
          <path fill="currentColor" fillRule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z" />
        </svg>

        <div className="flex min-w-0 flex-grow flex-col">
          <span className="truncate text-base font-medium">{title}</span>
          <span className="truncate text-xs text-zinc-400">{githubUrl}</span>
        </div>

        <svg className="h-5 w-5 flex-shrink-0 text-zinc-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
          <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
        </svg>
      </div>
    </a>;
};

Learn how to handle authentication flows with Privy and Base Account, including both Privy-managed authentication and custom backend verification.

## Overview

Privy handles the initial authentication flow, managing user sessions and wallet connections. You can also implement additional authentication layers for enhanced security or custom requirements.

The code snippets in this guide are based on the following example project:

<GithubRepoCard title="Base Account Privy Template" githubUrl="https://github.com/base/base-account-privy" />

## Authentication Flow

Privy manages the primary authentication before users enter your application:

<div style={{ display: 'flex', justifyContent: 'center'}}>
  <img src="https://mintcdn.com/base-a060aa97/Pikf3vnaPhlKo52m/images/base-account/privy-base-auth.gif?s=106dddb8cd8b19436f791e1aae317671" alt="Privy Base Auth" style={{ width: '600px', height: 'auto' }} width="800" height="645" data-path="images/base-account/privy-base-auth.gif" />
</div>

## Custom Authentication

For additional security or custom authentication requirements, you can implement backend verification using Sign-In with Ethereum (SIWE)
with the Base Account SDK.

### Setup

Follow the [Setup](/base-account/framework-integrations/privy/setup) guide to set up Privy with Base Account.

### Frontend Component (Sign In With Base)

We use the [`SignInWithBaseButton`](/base-account/reference/ui-elements/sign-in-with-base-button) component from the `@base-org/account-ui/react` package to make sure
we are following the brand guidelines.

<CodeGroup>
  ```tsx Authentication Component (components/sections/authentication.tsx) expandable theme={null}
  "use client";

  import { useState } from "react";
  import { useBaseAccountSdk } from "@privy-io/react-auth";
  import { SignInWithBaseButton } from "@base-org/account-ui/react";

  export const Authentication = () => {
    const { baseAccountSdk } = useBaseAccountSdk();
    const [loading, setLoading] = useState(false);
    const [verificationResult, setVerificationResult] = useState<any>(null);

    const provider = baseAccountSdk?.getProvider();

    const handleSignInWithBase = async () => {
      if (!provider) return;

      try {
        setLoading(true);

        // Get a fresh nonce from backend
        const nonceResponse = await fetch("/api/auth/nonce");
        const { nonce } = await nonceResponse.json();

        // Switch to Base Chain
        await provider.request({
          method: "wallet_switchEthereumChain",
          params: [{ chainId: "0x2105" }],
        });

        // Connect and authenticate with SIWE
        const response = (await provider.request({
          method: "wallet_connect",
          params: [{
            version: "1",
            capabilities: {
              signInWithEthereum: {
                nonce,
                chainId: "0x2105",
              },
            },
          }],
        })) as {
          accounts: {
            address: string;
            capabilities: {
              signInWithEthereum: { signature: string; message: string };
            };
          }[];
        };

        const { address } = response.accounts[0];
        const { message, signature } = response.accounts[0].capabilities.signInWithEthereum;

        // Verify with backend
        const verifyResponse = await fetch("/api/auth/verify", {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ address, message, signature }),
        });

        const result = await verifyResponse.json();
        setVerificationResult(result);
      } catch (error) {
        console.error("Sign in error:", error);
      } finally {
        setLoading(false);
      }
    };

    return (
      <div>
        <SignInWithBaseButton onClick={handleSignInWithBase} />
        {verificationResult && (
          <div>✅ Backend Verified! Address: {verificationResult.address}</div>
        )}
      </div>
    );
  };

  export default Authentication;
  ```
</CodeGroup>

### Using the Authentication Component

Add the Authentication component to your page to enable Sign In with Base functionality:

<CodeGroup>
  ```tsx Page Implementation (app/page.tsx) theme={null}
  import Authentication from "@/components/sections/authentication";

  export default function Home() {
    return (
      <main className="flex min-h-screen flex-col items-center justify-center p-24">
        <div className="z-10 w-full max-w-5xl items-center justify-between font-mono text-sm">
          <h1 className="text-4xl font-bold text-center mb-8">
            Base Account with Privy
          </h1>
          
          <div className="flex flex-col items-center space-y-4">
            <Authentication />
          </div>
        </div>
      </main>
    );
  }
  ```

  ```tsx Alternative: Protected Page (app/dashboard/page.tsx) theme={null}
  "use client";

  import { usePrivy } from "@privy-io/react-auth";
  import Authentication from "@/components/sections/authentication";

  export default function Dashboard() {
    const { authenticated } = usePrivy();

    if (!authenticated) {
      return (
        <div className="flex min-h-screen items-center justify-center">
          <div className="text-center">
            <h1 className="text-2xl font-bold mb-4">Access Required</h1>
            <p className="mb-6">Please authenticate to access the dashboard.</p>
            <Authentication />
          </div>
        </div>
      );
    }

    return (
      <div className="min-h-screen p-8">
        <h1 className="text-3xl font-bold mb-6">Dashboard</h1>
        <p>Welcome to your authenticated dashboard!</p>
        {/* Your protected content here */}
      </div>
    );
  }
  ```
</CodeGroup>

### Backend Implementation

<Warning>
  **Development Only**: This backend implementation is not production-ready. The nonce management system needs proper persistence and security enhancements for production use.
</Warning>

<CodeGroup>
  ```ts Nonce Generation (app/api/auth/nonce/route.ts) theme={null}
  import { NextResponse } from 'next/server';
  import crypto from 'crypto';
  import { nonceStore } from '@/lib/nonce-store';

  export async function GET() {
    try {
      const nonce = crypto.randomBytes(16).toString('hex');
      nonceStore.add(nonce);
      
      return NextResponse.json({ nonce });
    } catch (error) {
      return NextResponse.json(
        { error: 'Failed to generate nonce' },
        { status: 500 }
      );
    }
  }
  ```

  ```ts Signature Verification (app/api/auth/verify/route.ts) expandable theme={null}
  import { NextRequest, NextResponse } from 'next/server';
  import { createPublicClient, http } from 'viem';
  import { base } from 'viem/chains';
  import { nonceStore } from '@/lib/nonce-store';

  const client = createPublicClient({ 
    chain: base, 
    transport: http() 
  });

  export async function POST(request: NextRequest) {
    try {
      const { address, message, signature } = await request.json();

      // Extract nonce from SIWE message
      const nonce = message.match(/Nonce: (\w+)/)?.[1];
      
      if (!nonce || !nonceStore.consume(nonce)) {
        return NextResponse.json(
          { error: 'Invalid or reused nonce' },
          { status: 400 }
        );
      }

      // Verify signature using viem
      const valid = await client.verifyMessage({ 
        address: address as `0x${string}`, 
        message, 
        signature: signature as `0x${string}` 
      });

      if (!valid) {
        return NextResponse.json(
          { error: 'Invalid signature' },
          { status: 401 }
        );
      }

      return NextResponse.json({ 
        success: true, 
        address,
        timestamp: new Date().toISOString()
      });

    } catch (error) {
      return NextResponse.json(
        { error: 'Internal server error' },
        { status: 500 }
      );
    }
  }
  ```

  ```ts Nonce Store (lib/nonce-store.ts) expandable theme={null}
  // Simple in-memory nonce store
  // In production, use Redis or a database
  class NonceStore {
    private nonces = new Set<string>();

    add(nonce: string): void {
      this.nonces.add(nonce);
    }

    consume(nonce: string): boolean {
      return this.nonces.delete(nonce);
    }
  }

  export const nonceStore = new NonceStore();
  ```
</CodeGroup>

### Production Considerations

For production deployments, enhance the backend implementation with:

* **Persistent storage**: Use Redis or a database instead of in-memory storage
* **Rate limiting**: Implement request rate limiting for nonce generation
* **Session management**: Create proper JWT tokens or session cookies
* **Nonce expiration**: Add timestamp-based nonce expiration
