Skip to main content
When your agent calls a service, how does that service know it’s really your agent and not an impersonator? When your agent receives a response, how does it know the response came from a legitimate service? Identity, verification, and authentication solve these problems.

Why identity matters

In a world where agents interact with each other and with services autonomously, trust is the foundation. Without identity:
  • A service can’t verify that a request came from an authorized agent
  • Your agent can’t verify that a response came from the real service (not a malicious impersonator)
  • Other agents can’t discover what your agent does or how to interact with it
Identity standards on Base solve all three problems: they let your agent register itself in a public directory, prove its identity with every request, and discover other agents and services.

Registry: a public directory for agents

A registry is a public directory where agents and services publish their identity. Any participant can query the registry to resolve an agent’s address to its metadata: what it does, where its endpoints live, and which public key it uses for signing. On Base, this is implemented through the ERC-8004 standard. When your agent registers, its entry is stored onchain — anyone can verify it without relying on a central authority. A registry entry typically includes:
  • Your agent’s name and description
  • The endpoints where it can be reached
  • A that ties the agent’s identity to its cryptographic credentials

Register your agent

There are two ways to register your agent in the ERC-8004 registry:

Register via UI

Use 8004scan.io to register and explore registered agents through a web interface — no code required.

Register via SDK

Use the Agent0 SDK to register your agent programmatically and manage its onchain profile.
Learn more about the ERC-8004 standard →

Verification: proving identity at runtime

Registration tells the world your agent exists. Verification proves it’s really your agent making each request. This is handled by the ERC-8128 standard.
1

Register your agent

Your agent registers its identity and public key in the ERC-8004 registry. This is a one-time setup step.
2

Sign each request

When your agent calls a service, it signs the request using its private key. This creates a cryptographic signature unique to that specific request.
3

The service verifies the signature

The service looks up your agent’s public key from the registry, then checks the signature. If the signature matches, the service knows the request came from your registered agent and not an impersonator.
This works in both directions: your agent can also verify that a service’s response is authentic by checking the service’s signature against the registry. Learn more about Agent Verification (ERC-8128) →

Sign In With Agent (SIWA)

SIWA (Sign In With Agent) bundles ERC-8004 registration and ERC-8128 request signing into a single SDK — similar to how “Sign in with Google” bundles OAuth and identity into one integration. Instead of wiring up the two standards separately, you integrate SIWA and get both capabilities out of the box.
Start with SIWA for the simplest integration path. Use ERC-8004 and ERC-8128 directly only if you need fine-grained control over how your agent registers and how verification is performed.

How SIWA works

  1. The agent requests a nonce from the service, sending its address and agent ID.
  2. The service returns the nonce along with timestamps.
  3. The agent builds a SIWA message and signs it with its wallet.
  4. The agent sends the message and signature to the service.
  5. The service verifies the signature and calls the blockchain to confirm the agent owns that identity NFT.
  6. If verified, the service returns a receipt. The agent uses this for subsequent authenticated requests signed with ERC-8128.

Agent-side integration

Install the SIWA SDK:
Terminal
npm install @buildersgarden/siwa
Choose a signer based on your wallet provider. SIWA supports private keys, Bankr, Circle, Openfort, Privy, and smart contract accounts:
TypeScript
import { createLocalAccountSigner } from "@buildersgarden/siwa/signer";
import { privateKeyToAccount } from "viem/accounts";

const account = privateKeyToAccount(process.env.PRIVATE_KEY as `0x${string}`);
const signer = createLocalAccountSigner(account);
Request a nonce from the service, then sign and submit a SIWA message:
TypeScript
import { signSIWAMessage } from "@buildersgarden/siwa";

// Step 1: Request a nonce from the service
const nonceResponse = await fetch("https://api.example.com/siwa/nonce", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ address: await signer.getAddress() }),
});
const { nonce, issuedAt } = await nonceResponse.json();

// Step 2: Sign the SIWA message
const { message, signature } = await signSIWAMessage(
  {
    domain: "api.example.com",
    uri: "https://api.example.com/siwa",
    agentId: 42, // your ERC-8004 token ID
    agentRegistry: "eip155:8453:0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
    chainId: 8453,
    nonce,
    issuedAt,
  },
  signer
);

// Step 3: Submit for verification and receive a receipt
const verifyResponse = await fetch("https://api.example.com/siwa/verify", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ message, signature }),
});
const { receipt } = await verifyResponse.json();
Use the receipt to sign subsequent requests with ERC-8128:
TypeScript
import { signAuthenticatedRequest } from "@buildersgarden/siwa/erc8128";

const request = new Request("https://api.example.com/action", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ action: "transfer" }),
});

const signedRequest = await signAuthenticatedRequest(request, receipt, signer, 8453);
const response = await fetch(signedRequest);

Server-side verification

Services that want to accept SIWA-authenticated agents implement two endpoints: one to issue nonces and one to verify signatures.
TypeScript
import { verifySIWA, createSIWANonce } from "@buildersgarden/siwa";
import { createReceipt } from "@buildersgarden/siwa/receipt";
import { createPublicClient, http } from "viem";
import { base } from "viem/chains";

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

// POST /siwa/nonce
const { nonce, issuedAt } = await createSIWANonce({ address, agentId, agentRegistry }, client);

// POST /siwa/verify
const result = await verifySIWA(message, signature, "api.example.com", nonceValid, client);
if (result.success) {
  const { receipt } = createReceipt({ address: result.address, agentId: result.agentId });
  return { receipt };
}
SIWA ships drop-in middleware for Express, Next.js, Hono, and Fastify. See the SIWA documentation for framework-specific examples and advanced features including replay protection, criteria-based agent filtering, and x402 payment integration.

Next step

Agent apps

Build services designed for agents and make your app discoverable.