Skip to main content

Choosing An Authentication Method

Users in the Base app are authenticated with passkey account using Sign in with Ethereum (SIWE) or their Farcaster account using Sign in With Farcaster. When deciding between SIWE and SIWF, the core question is whether your app depends on Farcaster’s social context or must work outside Farcaster clients. auth-flow-chart

Sending Notifications

If your app plans to send notifications to users, you must use SIWF. Notifications require a Farcaster identity (FID), which is only available through Sign-in With Farcaster. You can still support SIWE if your app also needs a universal wallet-based identity, but SIWF is required for any notification functionality.

App location

If your app will be used on the open web, other wallets, or standalone mobile apps, use SIWE as your primary authentication. You can still offer SIWF when the user arrives from a Farcaster client.

Utilizing Farcaster Social Graph

If your app does not rely on followers, FIDs, casts, or social graph logic, use SIWE and optionally support SIWF for enhanced social features. If your app does rely on that data, consider if you are willing to require users to have a Farcaster account.
For a complete guide on authenticating users with SIWE, see our Authenticate Users guide using Sign in with Base.

Quick Auth

Quick Auth provides instant authentication by leveraging Farcaster’s identity system - no passwords, email verification, or complex OAuth flows required. When Quick Auth is called:
  • The user authenticates with a signature
  • The SDK returns a JWT that your backend verifies to confirm the user’s identity
  • The backend returns trusted data that can be used for sensitive actions
This differs from the Context API, which provides instant access to user information without authentication but cannot be trusted for sensitive operations.

Implementation

Step 1: Frontend Authentication

This code authenticates the user with Quick Auth, stores the JWT in memory, and uses it to verify the user’s identity with your backend.
App.tsx
import { useState } from "react";
import { sdk } from "@farcaster/miniapp-sdk";

export function App() {
 const [token, setToken] = useState<string | null>(null);
 const [userData, setUserData] = useState<{ fid: number} | null>(null);

 async function signIn() {
   try {
     const { token } = await sdk.quickAuth.getToken();
     setToken(token);
     
     // Use the token to authenticate the user and fetch authenticated user data
     const response = await sdk.quickAuth.fetch(`${BACKEND_ORIGIN}/auth`, {
       headers: { "Authorization": `Bearer ${token}` }
     });
     
     const data = await response.json();
     setUserData(data);
   } catch (error) {
     console.error("Authentication failed:", error);
   }
 }

 function signOut() {
   setToken(null);
   setUserData(null);
 }

 if (!token) {
   return <button onClick={signIn}>Sign In</button>;
 }

 return (
   <div>
     <p>Authenticated as FID: {userData?.fid}</p>
     <button onClick={signOut}>Sign Out</button>
   </div>
 );
}

Step 2: Backend Verification

Install the Quick Auth client:
npm install @farcaster/quick-auth
Quick Auth Client is the SDK that initiates the authentication flow in your application. Quick Auth Server is Farcaster’s service that handles signature verification and issues JWTs. When a user authenticates, the Quick Auth Server verifies their signature and issues a JWT. Your backend verifies this JWT using the @farcaster/quick-auth package.
route.tsx
// app/api/auth/route.ts
import { createClient, Errors } from '@farcaster/quick-auth';
import { NextRequest, NextResponse } from 'next/server';

const domain = 'your-domain.com'; // Must match your mini app's deployment domain
const client = createClient();

// This endpoint returns the authenticated user's FID 
export async function GET(request: NextRequest) {
  const authorization = request.headers.get('Authorization');
  if (!authorization?.startsWith('Bearer ')) {
    return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
  }

  const token = authorization.split(' ')[1];

  try {
    const payload = await client.verifyJwt({ token, domain });
    
    return NextResponse.json({
      fid: payload.sub,
    });
  } catch (e) {
    if (e instanceof Errors.InvalidTokenError) {
      return NextResponse.json({ error: 'Invalid token' }, { status: 401 });
    }
    throw e;
  }
}

Schema

JWT Payload

{
  "iat": 1747764819,
  "iss": "https://auth.farcaster.xyz",
  "exp": 1747768419,
  "sub": 6841,
  "aud": "your-domain.com" 
}
Payload fields:

iat
number
Issued at timestamp
iss
string
Quick Auth Server that issued the JWT
exp
number
Expiration timestamp (1 hour from issuance)
sub
number
User’s Farcaster ID (FID)
aud
string
Your mini app’s domain