From 6a7d1424e9e9ef4c7131501383a3f45354cb76ac Mon Sep 17 00:00:00 2001 From: Shreyaschorge Date: Thu, 10 Jul 2025 18:42:39 +0530 Subject: [PATCH] with backend support --- src/app/providers.tsx | 4 +- src/auth.ts | 84 +++--- .../ui/NeynarAuthButton/AuthDialog.tsx | 96 +++--- .../ui/NeynarAuthButton/ProfileButton.tsx | 38 +-- src/components/ui/NeynarAuthButton/index.tsx | 285 ++++++++++++++---- 5 files changed, 346 insertions(+), 161 deletions(-) diff --git a/src/app/providers.tsx b/src/app/providers.tsx index 2b335d8..90584eb 100644 --- a/src/app/providers.tsx +++ b/src/app/providers.tsx @@ -32,9 +32,7 @@ export function Providers({ backButtonEnabled={true} > - - {children} - + {children} diff --git a/src/auth.ts b/src/auth.ts index 8c39468..4d06956 100644 --- a/src/auth.ts +++ b/src/auth.ts @@ -1,8 +1,8 @@ -import { AuthOptions, getServerSession } from "next-auth" -import CredentialsProvider from "next-auth/providers/credentials"; -import { createAppClient, viemConnector } from "@farcaster/auth-client"; +import { AuthOptions, getServerSession } from 'next-auth'; +import CredentialsProvider from 'next-auth/providers/credentials'; +import { createAppClient, viemConnector } from '@farcaster/auth-client'; -declare module "next-auth" { +declare module 'next-auth' { interface Session { user: { fid: number; @@ -26,43 +26,50 @@ function getDomainFromUrl(urlString: string | undefined): string { } export const authOptions: AuthOptions = { - // Configure one or more authentication providers + // Configure one or more authentication providers providers: [ CredentialsProvider({ - name: "Sign in with Farcaster", + name: 'Sign in with Farcaster', credentials: { message: { - label: "Message", - type: "text", - placeholder: "0x0", + label: 'Message', + type: 'text', + placeholder: '0x0', }, signature: { - label: "Signature", - type: "text", - placeholder: "0x0", + label: 'Signature', + type: 'text', + placeholder: '0x0', + }, + nonce: { + label: 'Nonce', + type: 'text', + placeholder: 'Custom nonce (optional)', }, // In a production app with a server, these should be fetched from // your Farcaster data indexer rather than have them accepted as part // of credentials. // question: should these natively use the Neynar API? name: { - label: "Name", - type: "text", - placeholder: "0x0", + label: 'Name', + type: 'text', + placeholder: '0x0', }, pfp: { - label: "Pfp", - type: "text", - placeholder: "0x0", + label: 'Pfp', + type: 'text', + placeholder: '0x0', }, }, async authorize(credentials, req) { const csrfToken = req?.body?.csrfToken; - if (!csrfToken) { - console.error('CSRF token is missing from request'); + + const nonce = credentials?.nonce || csrfToken; + + if (!nonce) { + console.error('No nonce or CSRF token provided'); return null; } - const appClient = createAppClient({ ethereum: viemConnector(), }); @@ -73,8 +80,9 @@ export const authOptions: AuthOptions = { message: credentials?.message as string, signature: credentials?.signature as `0x${string}`, domain, - nonce: csrfToken, + nonce, }); + const { success, fid } = verifyResponse; if (!success) { @@ -100,30 +108,30 @@ export const authOptions: AuthOptions = { name: `next-auth.session-token`, options: { httpOnly: true, - sameSite: "none", - path: "/", - secure: true - } + sameSite: 'none', + path: '/', + secure: true, + }, }, callbackUrl: { name: `next-auth.callback-url`, options: { - sameSite: "none", - path: "/", - secure: true - } + sameSite: 'none', + path: '/', + secure: true, + }, }, csrfToken: { name: `next-auth.csrf-token`, options: { httpOnly: true, - sameSite: "none", - path: "/", - secure: true - } - } - } -} + sameSite: 'none', + path: '/', + secure: true, + }, + }, + }, +}; export const getSession = async () => { try { @@ -132,4 +140,4 @@ export const getSession = async () => { console.error('Error getting server session:', error); return null; } -} +}; diff --git a/src/components/ui/NeynarAuthButton/AuthDialog.tsx b/src/components/ui/NeynarAuthButton/AuthDialog.tsx index 2fc64d3..69c2c9a 100644 --- a/src/components/ui/NeynarAuthButton/AuthDialog.tsx +++ b/src/components/ui/NeynarAuthButton/AuthDialog.tsx @@ -12,7 +12,7 @@ export function AuthDialog({ }: { open: boolean; onClose: () => void; - url: string; + url?: string; isError: boolean; error?: Error | null; step: 'signin' | 'access' | 'loading'; @@ -47,49 +47,49 @@ export function AuthDialog({ return { title: 'Grant Access', description: ( -
-

+

+

Allow this app to access your Farcaster account:

-
-
-
+
+
+
-
+
Read Access
-
+
View your profile and public information
-
-
+
+
- +
-
+
Write Access
-
+
Post casts, likes, and update your profile
@@ -118,43 +118,43 @@ export function AuthDialog({ const content = getStepContent(); return ( -
-
-
-

+
+
+
+

{isError ? 'Error' : content.title}

{isError ? ( -
-
+
+
{error?.message || 'Unknown error, please try again.'}
) : ( -
-
+
+
{typeof content.description === 'string' ? ( -

+

{content.description}

) : ( @@ -162,23 +162,23 @@ export function AuthDialog({ )}
-
+
{content.showQR && content.qrUrl ? ( -
+
{/* eslint-disable-next-line @next/next/no-img-element */} QR Code
) : step === 'loading' || isLoading ? ( -
-
-
- +
+
+
+ {step === 'loading' ? 'Setting up access...' : 'Loading...'} @@ -204,7 +204,7 @@ export function AuthDialog({ '_blank' ) } - className='btn btn-outline flex items-center justify-center gap-2 w-full' + className="btn btn-outline flex items-center justify-center gap-2 w-full" > I'm using my phone → diff --git a/src/components/ui/NeynarAuthButton/ProfileButton.tsx b/src/components/ui/NeynarAuthButton/ProfileButton.tsx index daec476..bcf1ca7 100644 --- a/src/components/ui/NeynarAuthButton/ProfileButton.tsx +++ b/src/components/ui/NeynarAuthButton/ProfileButton.tsx @@ -20,7 +20,7 @@ export function ProfileButton({ const pfpUrl = userData?.pfpUrl ?? 'https://farcaster.xyz/avatar.png'; return ( -
+
{showDropdown && ( -
+
)} {/* Unified Auth Dialog */} - {url && ( + { { setShowDialog(false); setDialogStep('signin'); @@ -423,7 +602,7 @@ export function NeynarAuthButton() { isLoading={signersLoading} signerApprovalUrl={signerApprovalUrl} /> - )} + } ); }