跳至主要内容
小龙虾小龙虾AI
🤖

Sign-in with Agent

SIWA (Sign-In With Agent) authentication for ERC-8004 registered agents.

下载730
星标0
版本0.0.4
安全合规
安全通过
🔗API

技能说明


name: siwa version: 0.2.0 description: > SIWA (Sign-In With Agent) authentication for ERC-8004 registered agents.

SIWA SDK

Sign-In With Agent (SIWA) lets AI agents authenticate with services using their ERC-8004 onchain identity.

Install

npm install @buildersgarden/siwa

Skills

Agent-Side (Signing)

Choose based on your wallet provider:

  • Bankr — Bankr Agent API wallets
  • Circle — Circle developer-controlled wallets
  • Privy — Privy server wallets
  • Private Key — Raw private key (viem LocalAccount)
  • Keyring Proxy — Self-hosted proxy with optional 2FA

Server-Side (Verification)

SDK Modules

ImportDescription
@buildersgarden/siwaCore: signSIWAMessage, verifySIWA, createSIWANonce, parseSIWAMessage, buildSIWAMessage, createClientResolver, parseChainId
@buildersgarden/siwa/signerSigner factories (see wallet-specific skills above)
@buildersgarden/siwa/erc8128ERC-8128 HTTP signing/verification
@buildersgarden/siwa/receiptHMAC receipt helpers
@buildersgarden/siwa/nonce-storeNonce stores (Memory, Redis, KV)
@buildersgarden/siwa/identitySIWA_IDENTITY.md helpers
@buildersgarden/siwa/registryOnchain agent registration
@buildersgarden/siwa/client-resolverDynamic PublicClient resolution for multi-chain servers
@buildersgarden/siwa/nextNext.js middleware (withSiwa, siwaOptions)
@buildersgarden/siwa/expressExpress middleware (siwaMiddleware, siwaJsonParser, siwaCors)
@buildersgarden/siwa/honoHono middleware (siwaMiddleware, siwaCors)
@buildersgarden/siwa/fastifyFastify middleware (siwaPlugin, siwaAuth)
@buildersgarden/siwa/x402x402 payment helpers
@buildersgarden/siwa/captchaReverse CAPTCHA (prove you're an AI)

x402 Payments (Agent-Side)

When an API requires payment, it returns HTTP 402 with a Payment-Required header. The agent decodes the payment options, constructs a signed payment, and retries with a Payment-Signature header — all while maintaining SIWA authentication.

Handling a 402 Response

import {
  encodeX402Header,
  decodeX402Header,
  type PaymentRequired,
  type PaymentPayload,
} from "@buildersgarden/siwa/x402";
import { signAuthenticatedRequest } from "@buildersgarden/siwa/erc8128";

// 1. Make initial authenticated request (may get 402)
const signedRequest = await signAuthenticatedRequest(
  new Request("https://api.example.com/premium", { method: "POST" }),
  receipt,
  signer,
  84532,
);

const res = await fetch(signedRequest);

if (res.status === 402) {
  // 2. Decode payment requirements from header
  const header = res.headers.get("Payment-Required");
  const { accepts, resource } = decodeX402Header<PaymentRequired>(header!);

  // 3. Pick a payment option and construct payload
  const option = accepts[0];
  const payload: PaymentPayload = {
    signature: "0x...",  // sign the payment with your wallet
    payment: {
      scheme: option.scheme,
      network: option.network,
      amount: option.amount,
      asset: option.asset,
      payTo: option.payTo,
    },
    resource,
  };

  // 4. Retry with both SIWA auth + payment header
  const retryRequest = await signAuthenticatedRequest(
    new Request("https://api.example.com/premium", {
      method: "POST",
      headers: {
        "Payment-Signature": encodeX402Header(payload),
      },
    }),
    receipt,
    signer,
    84532,
  );

  const paidRes = await fetch(retryRequest);
  // paidRes.headers.get("Payment-Response") contains { txHash, ... }
}

x402 Headers

HeaderDirectionDescription
Payment-RequiredServer → AgentBase64-encoded JSON with accepted payment options. Sent with 402.
Payment-SignatureAgent → ServerBase64-encoded signed payment payload.
Payment-ResponseServer → AgentBase64-encoded settlement result with transaction hash.

Pay-Once Sessions

Some endpoints use pay-once mode: the first request requires payment, subsequent requests from the same agent to the same resource pass through without payment until the session expires. If you receive a 200 on a previously-paid endpoint, the session is still active — no need to pay again.


Captcha (Reverse CAPTCHA)

SIWA includes a "reverse CAPTCHA" mechanism — inspired by MoltCaptcha — that proves an entity is an AI agent, not a human. Challenges exploit how LLMs generate text in a single autoregressive pass (satisfying multiple constraints simultaneously), while humans must iterate.

Two integration points:

  1. Sign-in flow — server requires captcha before issuing a nonce
  2. Per-request — middleware randomly challenges agents during authenticated API calls

Agent-Side: Handling a Captcha Challenge

The SDK provides two convenience wrappers for the captcha retry pattern:

Sign-In Captcha: solveCaptchaChallenge()

import { solveCaptchaChallenge } from "@buildersgarden/siwa/captcha";

// 1. Request nonce
const nonceRes = await fetch("/api/siwa/nonce", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ address, agentId, agentRegistry }),
});
const data = await nonceRes.json();

// 2. Detect + solve captcha if required
const captcha = await solveCaptchaChallenge(data, async (challenge) => {
  // LLM generates text satisfying all constraints in a single pass
  // challenge: { topic, format, lineCount, asciiTarget, wordCount?, timeLimitSeconds, ... }
  // Your LLM generates text satisfying all constraints in one pass.
  // Use any provider (Anthropic, OpenAI, etc.) — the solver just returns a string.
  return await generateText(challenge);
});

if (captcha.solved) {
  // 3. Retry with challenge response
  const retryRes = await fetch("/api/siwa/nonce", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ address, agentId, agentRegistry, challengeResponse: captcha.challengeResponse }),
  });
}

Per-Request Captcha: retryWithCaptcha()

import { signAuthenticatedRequest, retryWithCaptcha } from "@buildersgarden/siwa/erc8128";

const url = "https://api.example.com/action";
const body = JSON.stringify({ key: "value" });

// 1. Sign and send
const signed = await signAuthenticatedRequest(
  new Request(url, { method: "POST", body }),
  receipt, signer, chainId,
);
const response = await fetch(signed);

// 2. Detect + solve captcha, re-sign, and get retry request
const result = await retryWithCaptcha(
  response,
  new Request(url, { method: "POST", body }), // fresh request (original body consumed)
  receipt, signer, chainId,
  async (challenge) => generateText(challenge), // your LLM solver
);

if (result.retry) {
  const retryResponse = await fetch(result.request);
}

Note: Pass a fresh, unconsumed Request to retryWithCaptcha — the original is consumed after signing/sending.

Difficulty Levels

LevelTime LimitConstraints
easy30sLine count + ASCII sum of first chars
medium20s+ word count
hard15s+ character at specific position
extreme10s+ total character count

Links

如何使用「Sign-in with Agent」?

  1. 打开小龙虾AI(Web 或 iOS App)
  2. 点击上方「立即使用」按钮,或在对话框中输入任务描述
  3. 小龙虾AI 会自动匹配并调用「Sign-in with Agent」技能完成任务
  4. 结果即时呈现,支持继续对话优化

相关技能