This project is a work in progress. APIs and documentation may change.

SIWA

Sign In With Agent

Trustless identity and authentication for AI agents. An open standard built on ERC-8004 and ERC-8128.

Give your agent one prompt and it will create a wallet, register onchain, and start authenticating.

Read https://siwa.builders.garden/skill.md
  1. 1.Read the skill file above
  2. 2.Create your wallet & register onchain
  3. 3.Authenticate with any SIWA server
View skill.md
For Agents

Prove who you are

Read a skill file, get an onchain identity, and authenticate with any service — autonomously, without exposing your keys.

For Agent Builders

Give your agent an identity

Register your agent onchain, store its keys safely, and let it authenticate with any service — one open standard.

For Platform Builders

Gate your platform for agents

Know which agent is calling your API. Verify its identity on every request — no API keys, no shared secrets.

Why SIWA

Keys never touch the agent

Private keys are stored in a separate secure service. The agent can request signatures but never access the key — even if the agent is compromised.

Identity lives onchain

Each agent gets an ERC-721 NFT on the Identity Registry. Transferable, verifiable, permanent — anyone can check it.

Works on any chain

Base, Ethereum, Linea, Polygon. Deploy on mainnet or testnets — wherever your agents live.

Open standard

MIT licensed, built on ERC-8004 and ERC-8128. Works with any agent framework — Claude, GPT, custom agents.

How It Works

1

Agent gets an identity

Create a wallet via the keyring proxy and register an onchain NFT on the Identity Registry.

2

Agent signs a message

Build a structured SIWA message and sign it. The private key never leaves the keyring.

3

Server verifies onchain

Check the signature, verify NFT ownership on the registry, and grant access.

Quickstart

Install the SDK and add two functions — one on the agent, one on the server.

$npm install @buildersgarden/siwa
agent.tsAgent
import { signSIWAMessage } from '@buildersgarden/siwa';

// address is resolved from the keystore
const { message, signature, address } = await signSIWAMessage(
  {
    domain: 'api.example.com',
    uri: 'https://api.example.com',
    agentId,
    agentRegistry,
    chainId,
    nonce,
    issuedAt: new Date().toISOString(),
  },
  keystoreConfig
);
server.tsServer
import { verifySIWA } from '@buildersgarden/siwa';
import { createPublicClient, http } from 'viem';

const client = createPublicClient({ transport: http() });

const result = await verifySIWA(
  message,
  signature,
  'api.example.com',
  (nonce) => nonceStore.check(nonce),
  client
);

// result.valid, result.address, result.agentId