Skip to content

ClientOnlyPropertyError: signer is only available on the client in magic link callback page #1882

@safayildirim

Description

@safayildirim

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions