This project is a work in progress. Use at your own risk — we welcome feedback and contributions.

Your API can't tell agents from humans.

Sign-in with Agent lets your server authenticate AI agents and filter out humans. Built on ERC-8004 and ERC-8128.

Read https://siwa.id/skill.md
  1. 1.Read the skill file above
  2. 2.Get a wallet (any provider works)
  3. 3.Register onchain as an ERC-8004 agent
  4. 4.Authenticate with any SIWA-compatible service
View skill.md

How It Works

Phase 1 — Sign-In

ERC-8004

Agent proves its onchain identity. The server verifies NFT ownership on the ERC-8004 registry, checks the signer type, and issues a session receipt.

Phase 2 — Session

ERC-8128

Every subsequent API call is signed. The server verifies the signature and receipt on each request — no tokens, no API keys.

For Servers

One SDK, full control over who calls your API.

Ownership

Verify the agent owns its ERC-8004 identity onchain.

Signer type

Enforce EOA-only, smart account-only, or allow both.

Framework support

Drop-in middleware for Next.js, Express, Hono, and Fastify.

Registry criteria

Query score, reputation, services, required trust level, crypto-economic guarantees, and TEE attestation from the ERC-8004 registry.

Per-request signing

Every API call is cryptographically signed with ERC-8128. No bearer tokens, no shared secrets.

Agentic captchaComing soon

Challenge callers to prove they're agents, not humans.

For Agents

Your agent already knows how to authenticate.

Give your agent the SIWA skill or use the SDK directly. It learns what messages to sign, how to sign them, and how to maintain an authenticated session.

1

Get a wallet

Use any provider: Bankr, Circle, Openfort, Privy, private key, keyring proxy, or others.

2

Register onchain

Mint an ERC-8004 identity NFT on the registry.

3

Authenticate

Sign in with SIWA, then sign every request with ERC-8128.

Agent Skill

Paste this into your agent to teach it the full SIWA authentication flow:

Read https://siwa.id/skill.md

Quickstart

Two functions — one on the agent to sign, one on the server to verify.

$npm install @buildersgarden/siwa
agent.tsAgent
import { signSIWAMessage } from "@buildersgarden/siwa";
import { createLocalAccountSigner } from "@buildersgarden/siwa/signer";
// Use any wallet - Openfort, Privy, private key, etc.
const signer = createLocalAccountSigner(account);
const { message, signature } = await signSIWAMessage({
domain: "api.example.com",
uri: "https://api.example.com/siwa",
agentId: 42,
agentRegistry: "eip155:84532:0x8004...",
chainId: 84532,
nonce,
issuedAt: new Date().toISOString(),
}, signer);
server.tsServer
import { createSIWANonce, verifySIWA } from "@buildersgarden/siwa";
import { createMemorySIWANonceStore } from "@buildersgarden/siwa/nonce-store";
import { createPublicClient, http } from "viem";
import { baseSepolia } from "viem/chains";
const client = createPublicClient({
chain: baseSepolia, transport: http(),
});
const nonceStore = createMemorySIWANonceStore();
// Nonce endpoint — issue
const nonce = await createSIWANonce(params, client, { nonceStore });
// Verify endpoint — consume
const result = await verifySIWA(
message, signature, "api.example.com",
{ nonceStore }, client,
);
// result.valid, result.agentId, result.address