Skip to main content
Use MiniKit.walletAuth() to authenticate a user with Sign-In with Ethereum inside World App. This is the recommended authentication flow for mini apps.
These examples assume MiniKit has already been initialized through MiniKitProvider or MiniKit.install().

Availability

  • Works natively in World App
  • Can execute outside World App through Wagmi or a custom fallback when configured

Basic Usage

Generate the nonce on your backend. The nonce must be alphanumeric and at least 8 characters.
"use client";

import { MiniKit } from "@worldcoin/minikit-js";
import type {
  CommandResultByVia,
  MiniKitWalletAuthOptions,
  WalletAuthResult,
} from "@worldcoin/minikit-js/commands";

export async function signInWithWallet() {
  const response = await fetch("/api/nonce");
  const { nonce } = await response.json();

  const input = {
    nonce,
    statement: "Sign in to Example Mini App",
    expirationTime: new Date(Date.now() + 1000 * 60 * 60),
    // requestId: "optional-tracking-id",
    // notBefore: new Date(),
  } satisfies MiniKitWalletAuthOptions;

  const result: CommandResultByVia<WalletAuthResult> =
    await MiniKit.walletAuth(input);

  if (result.executedWith === "fallback") {
    return;
  }

  await fetch("/api/complete-siwe", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      payload: result.data,
      nonce,
    }),
  });
}

Result

type WalletAuthResponse =
  | {
      executedWith: "minikit" | "wagmi";
      data: {
        address: string;
        message: string;
        signature: string;
      };
    }
  | {
      executedWith: "fallback";
      data: unknown;
    };

Fallback Behavior

  • executedWith: "wagmi" means the Wagmi integration handled the request
  • executedWith: "fallback" means your custom fallback function handled the request
Use executedWith to branch on the runtime path when needed.

Backend Verification

Always verify the returned SIWE payload on your backend.
import { cookies } from "next/headers";
import { NextRequest, NextResponse } from "next/server";
import type { MiniAppWalletAuthSuccessPayload } from "@worldcoin/minikit-js/commands";
import { verifySiweMessage } from "@worldcoin/minikit-js/siwe";

type RequestBody = {
  payload: MiniAppWalletAuthSuccessPayload;
  nonce: string;
};

export async function POST(req: NextRequest) {
  const { payload, nonce } = (await req.json()) as RequestBody;

  if (nonce !== cookies().get("siwe")?.value) {
    return NextResponse.json(
      { isValid: false, error: "Invalid nonce" },
      { status: 400 },
    );
  }

  try {
    // Optional: pass statement and requestId for additional server-side validation
    const verification = await verifySiweMessage(
      payload,
      nonce,
      // statement,  — validates the statement matches what you sent
      // requestId,  — validates the request ID matches what you sent
      // viemClient, — custom viem Client; defaults to a public Worldchain client
    );

    return NextResponse.json({
      isValid: verification.isValid,
      address: verification.siweMessageData.address,
    });
  } catch (error) {
    return NextResponse.json(
      {
        isValid: false,
        error: error instanceof Error ? error.message : "Unknown error",
      },
      { status: 400 },
    );
  }
}

Options

FieldTypeRequiredDescription
noncestringYesAlphanumeric, at least 8 characters
statementstringNoHuman-readable statement included in the SIWE message
expirationTimeDateNoWhen the SIWE message expires
notBeforeDateNoSIWE message is not valid before this time
requestIdstringNoArbitrary ID for correlating the request on your backend
fallback() => Promise<T>NoCustom fallback for non-World-App environments

Notes

  • Use MiniKit.user.walletAddress after successful auth if you need cached user state
  • Use MiniKit.getUserByAddress() or MiniKit.getUserByUsername() to resolve username and profile metadata
  • Do not use World ID verification as a login substitute

Error Codes

CodeMeaning
malformed_requestThe SIWE request payload is invalid
user_rejectedThe user rejected the signature request
generic_errorUnexpected failure

Preview