-
Notifications
You must be signed in to change notification settings - Fork 188
Description
Problem Summary
Getting "ClientOnlyPropertyError: signer is only available on the client" error when using useAuthenticate hook in a magic link callback page, even though the component is marked as "use client".
Environment
Framework: Next.js 15.3.5
Account Kit Version: @account-kit/react ^4.53.1
Authentication Method: Magic Link (emailMode: "magicLink")
Component: app/(auth)/login/callback/page.tsx
Error Details
Magic link redirect error ClientOnlyPropertyError: signer is only available on the client
Version: 4.53.1
at useAuthenticate.useMutation [as mutationFn] (useAuthenticate.ts:65:17)
at Object.fn (mutation.ts:174:29)
at run (retryer.ts:153:49)
at Object.start (retryer.ts:218:9)
at Mutation.execute (mutation.ts:213:40)
Code Reproduction
//app/(auth)/login/callback/page.tsx
"use client";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { useAuthenticate } from "@account-kit/react";
export default function Page() {
const router = useRouter();
const [isClient, setIsClient] = useState(false);
const { authenticate } = useAuthenticate();
useEffect(() => {
setIsClient(true);
}, []);
useEffect(() => {
if (!isClient) return;
const handleRedirect = () => {
const url = new URL(window.location.href);
const bundle = url.searchParams.get("bundle");
if (bundle) {
authenticate({
type: "email",
bundle,
}, {
onSuccess: () => router.replace("/dashboard"),
onError: (error) => {
console.error("Magic link redirect error", error); // ❌ Error occurs here
router.replace("/login?error=magic-link");
},
});
}
};
handleRedirect();
}, [router, isClient, authenticate]);
if (!isClient) return <div>Loading...</div>;
return <div>Completing login...</div>;
}
Configuration
alchemy.config.ts
export const config = createConfig(
{
transport: alchemy({
apiKey: process.env.NEXT_PUBLIC_ALCHEMY_API_KEY || "",
}),
chain: sepolia,
ssr: true,
storage: cookieStorage,
enablePopupOauth: true,
},
{
auth: {
sections: [
[{ type: "email", emailMode: "magicLink" }],
[
{ type: "passkey" },
{
type: "social",
authProviderId: "google",
mode: "popup",
},
],
],
addPasskeyOnSignup: true,
},
}
);
Expected Behavior
The useAuthenticate hook should work properly in a client-side component without throwing "signer is only available on the client" errors.
Actual Behavior
The hook throws an error during component initialization, preventing magic link authentication from working.
Root Cause Analysis
The issue appears to be that even with "use client" directive:
The useAuthenticate hook is called during component initialization
The Account Kit context/signer is not fully available at that moment
This causes the "signer is only available on the client" error