|
1 | 1 | --- |
2 | 2 | title: Authentication |
3 | | -description: Let users start fast and ask for a wallet only when needed |
| 3 | +description: Quick Auth provides instant authentication by leveraging Farcaster's identity system - no passwords, email verification, or complex OAuth flows required. |
4 | 4 | --- |
5 | 5 |
|
6 | | -## Authentication guidance from Base App |
| 6 | +When Quick Auth is called: |
7 | 7 |
|
8 | | -<Warning> |
9 | | -Save authentication that requires an interaction for interactions that require it (e.g., buying something, viewing personalized pages). |
10 | | -</Warning> |
| 8 | +* The user authenticates with a signature |
| 9 | +* The SDK returns a JWT that your backend verifies to confirm the user's identity |
| 10 | +* The backend returns trusted data that can be used for sensitive actions |
11 | 11 |
|
12 | | -Supported approaches: |
| 12 | +<Tip> |
| 13 | +This differs from the [Context API](/mini-apps/core-concepts/context), which provides instant access to user information without authentication but cannot be trusted for sensitive operations. |
| 14 | +</Tip> |
13 | 15 |
|
14 | | -<Tabs> |
15 | | -<Tab title="Sign In with Farcaster / Quick Auth"> |
16 | | -Base App natively supports SIWF in-app, enabling social identity without leaving the app. Quick Auth can issue a JWT to persist session state. |
17 | 16 |
|
18 | | -**User Experience in Base App:** |
19 | | -- **Create Account Users** (new Farcaster accounts created during Base App onboarding): Users see a "Login request" tray with the SIWF message and can sign it directly with their passkey |
20 | | -- **Connect Account Users** (existing Farcaster accounts connected during onboarding): Users are prompted to deeplink to Farcaster one-time only to register their wallet as an auth address, then enjoy seamless in-app sign-in thereafter |
21 | | -</Tab> |
| 17 | +## Implementation |
22 | 18 |
|
23 | | -<Tab title="Wallet Auth"> |
24 | | -Base App provides an in‑app smart wallet that doesn't require app switching. Use wallet auth for a persisted session when necessary, but avoid gating initial exploration behind connect. |
25 | | -</Tab> |
| 19 | +### Step 1: Frontend Authentication |
26 | 20 |
|
27 | | -<Tab title="Context Data"> |
28 | | -All hosts return context data (including user). Use it for analytics or lightweight session hints, but **do not treat as primary auth** since context data can be spoofed by developers who create their own mini app hosts. |
29 | | -</Tab> |
30 | | -</Tabs> |
| 21 | +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. |
31 | 22 |
|
| 23 | + ```jsx App.tsx |
| 24 | +import { useState } from "react"; |
| 25 | +import { sdk } from "@farcaster/miniapp-sdk"; |
32 | 26 |
|
33 | | -## Implementation Example |
| 27 | +export function App() { |
| 28 | + const [token, setToken] = useState<string | null>(null); |
| 29 | + const [userData, setUserData] = useState<{ fid: number} | null>(null); |
34 | 30 |
|
35 | | -```tsx App.tsx |
36 | | -import { useMiniKit, useAuthenticate } from '@coinbase/onchainkit/minikit'; |
| 31 | + async function signIn() { |
| 32 | + try { |
| 33 | + const { token } = await sdk.actions.quickAuth(); |
| 34 | + setToken(token); |
| 35 | + |
| 36 | + // Use the token to authenticate the user and fetch authenticated user data |
| 37 | + const response = await sdk.quickAuth.fetch(`${BACKEND_ORIGIN}/auth`, { |
| 38 | + headers: { "Authorization": `Bearer ${token}` } |
| 39 | + }); |
| 40 | + |
| 41 | + const data = await response.json(); |
| 42 | + setUserData(data); |
| 43 | + } catch (error) { |
| 44 | + console.error("Authentication failed:", error); |
| 45 | + } |
| 46 | + } |
37 | 47 |
|
38 | | -function MyComponent() { |
39 | | - const { context } = useMiniKit(); |
40 | | - const { user } = useAuthenticate(); |
| 48 | + function signOut() { |
| 49 | + setToken(null); |
| 50 | + setUserData(null); |
| 51 | + } |
| 52 | + |
| 53 | + if (!token) { |
| 54 | + return <button onClick={signIn}>Sign In</button>; |
| 55 | + } |
41 | 56 |
|
42 | | - // ✅ Safe: Use context for analytics only |
43 | | - const userFid = context.user.fid; // For analytics tracking |
44 | | - |
45 | | - // ✅ Safe: Use cryptographic verification for auth |
46 | | - const verifiedUser = user; // From SIWF or wallet auth |
47 | | - |
48 | | - // ❌ Unsafe: Don't rely on context for primary auth |
49 | | - // const isAuthenticated = !!context.user.fid; // Can be spoofed! |
50 | | - |
51 | 57 | return ( |
52 | 58 | <div> |
53 | | - {/* Use verified user data for secure operations */} |
| 59 | + <p>Authenticated as FID: {userData?.fid}</p> |
| 60 | + <button onClick={signOut}>Sign Out</button> |
54 | 61 | </div> |
55 | 62 | ); |
56 | 63 | } |
57 | 64 | ``` |
58 | 65 |
|
59 | | -<Info> |
60 | | -For a complete example of using Quick Auth with MiniKit, see [here](https://github.com/coinbase/onchainkit/blob/main/examples/minikit-example/app/components/UserInfo.tsx). |
61 | | -</Info> |
| 66 | +### Step 2: Backend Verification |
62 | 67 |
|
63 | | -## Best practices |
| 68 | +Install the Quick Auth client: |
64 | 69 |
|
65 | | -- Gate wallet only at the point of onchain action |
66 | | -- Prefer SIWF/Quick Auth for low‑friction identity |
67 | | -- Use context for analytics; avoid using it as primary auth |
68 | | -- Handle Base App's different authentication flows gracefully |
69 | | -- Always use cryptographic verification for security-critical operations |
| 70 | +```bash |
| 71 | +npm install @farcaster/quick-auth |
| 72 | +``` |
70 | 73 |
|
71 | | -Further reading: |
| 74 | +**Quick Auth Client** is the SDK that initiates the authentication flow in your application. |
| 75 | +
|
| 76 | +**Quick Auth Server** is Farcaster's service that handles signature verification and issues JWTs. |
| 77 | +
|
| 78 | +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. |
| 79 | +
|
| 80 | +```jsx route.tsx |
| 81 | +// app/api/auth/route.ts |
| 82 | +import { createClient, Errors } from '@farcaster/quick-auth'; |
| 83 | +import { NextRequest, NextResponse } from 'next/server'; |
| 84 | + |
| 85 | +const domain = 'your-domain.com'; // Must match your mini app's deployment domain |
| 86 | +const client = createClient(); |
| 87 | + |
| 88 | +// This endpoint returns the authenticated user's FID |
| 89 | +export async function GET(request: NextRequest) { |
| 90 | + const authorization = request.headers.get('Authorization'); |
| 91 | + if (!authorization?.startsWith('Bearer ')) { |
| 92 | + return NextResponse.json({ error: 'Unauthorized' }, { status: 401 }); |
| 93 | + } |
| 94 | + |
| 95 | + const token = authorization.split(' ')[1]; |
| 96 | + |
| 97 | + try { |
| 98 | + const payload = await client.verifyJwt({ token, domain }); |
| 99 | + |
| 100 | + return NextResponse.json({ |
| 101 | + fid: payload.sub, |
| 102 | + }); |
| 103 | + } catch (e) { |
| 104 | + if (e instanceof Errors.InvalidTokenError) { |
| 105 | + return NextResponse.json({ error: 'Invalid token' }, { status: 401 }); |
| 106 | + } |
| 107 | + throw e; |
| 108 | + } |
| 109 | +} |
| 110 | +``` |
72 | 111 |
|
73 | | -<CardGroup cols={2}> |
74 | | - <Card title="useAuthenticate" icon="book-open" href="/mini-apps/technical-reference/minikit/hooks/useAuthenticate" /> |
75 | | - <Card title="Provider & Initialization" icon="cog" href="/mini-apps/technical-reference/minikit/provider-and-initialization" /> |
76 | | -</CardGroup> |
| 112 | +## Schema |
| 113 | +
|
| 114 | +### JWT Payload |
| 115 | +
|
| 116 | +
|
| 117 | +```json |
| 118 | +{ |
| 119 | + "iat": 1747764819, |
| 120 | + "iss": "https://auth.farcaster.xyz", |
| 121 | + "exp": 1747768419, |
| 122 | + "sub": 6841, |
| 123 | + "aud": "your-domain.com" |
| 124 | +} |
| 125 | +``` |
| 126 | +Payload fields: |
| 127 | +
|
| 128 | +<Card> |
| 129 | +<ParamField path="iat" type="number"> |
| 130 | +Issued at timestamp |
| 131 | +</ParamField> |
| 132 | +
|
| 133 | +<ParamField path="iss" type="string"> |
| 134 | +Quick Auth Server that issued the JWT |
| 135 | +</ParamField> |
| 136 | +
|
| 137 | +<ParamField path="exp" type="number"> |
| 138 | +Expiration timestamp (1 hour from issuance) |
| 139 | +</ParamField> |
77 | 140 |
|
| 141 | +<ParamField path="sub" type="number"> |
| 142 | +User's Farcaster ID (FID) |
| 143 | +</ParamField> |
78 | 144 |
|
| 145 | +<ParamField path="aud" type="string"> |
| 146 | +Your mini app's domain |
| 147 | +</ParamField> |
| 148 | +</Card> |
| 149 | +
|
| 150 | +
|
| 151 | +<CardGroup cols={2}> |
| 152 | +<Card title="useAuthenticate" href="/mini-apps/technical-reference/minikit/hooks/useAuthenticate"> |
| 153 | + use Minikit's useAuthenticate hook to authenticate users. |
| 154 | +</Card> |
| 155 | +<Card title="Context" href="/mini-apps/core-concepts/context"> |
| 156 | + Understand how context is used in mini apps. |
| 157 | +</Card> |
| 158 | +</CardGroup> |
79 | 159 |
|
0 commit comments