⚡ Solana-native · Ed25519 · Zero browsers · Built by The Shellborn Collective

Sign In With Agent

Like "Sign In With Google" — but for AI agents. No OAuth. No browsers. No humans in the loop. Just cryptography.

agent@siwa ~ authentication
# Agent requests a challenge
GET /siwa/challenge?pubkey=7xKN...mQ4p
{ challenge: "a1b2c3d4...", nonce: "xK9mZ..." }
 
# Agent signs with Ed25519 keypair
signature = nacl.sign.detached(message, secretKey)
 
# Service verifies and creates session
POST /siwa/verify { message, pubkey, signature }
{ token: "siwa_eyJ...", expires: "2026-02-08T..." }
 
✓ Authenticated. No browser. No human. Just math.
GET /api/data Authorization: Bearer siwa_eyJ...
How It Works

Four steps. Zero friction.

Agents authenticate the same way they sign transactions — with their keypair. No OAuth flows, no browser redirects, no consent screens.

01

Request Challenge

Agent sends its public key to the service. Service returns a unique challenge message with a nonce and expiration.

GET /siwa/challenge
02

Sign Message

Agent signs the challenge with its Ed25519 private key. This proves identity without revealing the secret key.

nacl.sign.detached()
03

Verify Signature

Service verifies the signature matches the public key. Checks domain, nonce, and timing to prevent replay attacks.

POST /siwa/verify
04

Session Token

On success, the service issues a bearer token. The agent uses this for all subsequent API calls until expiry.

Bearer siwa_eyJ...
Why SIWA?

Agents don't have browsers.

Existing auth methods were designed for humans. SIWA was designed for machines.

SIWA OAuth 2.0 API Keys SIWE
No browser required
No human in the loop ~
Cryptographic identity
Replay protection
Self-provisioning
Solana-native
Built for agents
Credential-free
Quick Start

Three lines to authenticate.

Drop-in client for agents, Express middleware for services. TypeScript-first, zero config.

import { SIWAClient } from '@siwa/client';
import { Keypair } from '@solana/web3.js';

// Create client with agent's keypair
const client = new SIWAClient({
  keypair: Keypair.generate(),  // or load from file
});

// Authenticate with any SIWA-enabled service
const session = await client.signIn('https://api.example.com');

// Use the session token for API calls
const authedFetch = client.authenticatedFetch(session);
const data = await authedFetch('/api/protected');
import express from 'express';
import { SIWAServer } from '@siwa/server';

const app = express();
const siwa = new SIWAServer({
  domain: 'api.example.com',
  uri: 'https://api.example.com',
  statement: 'Sign in to Example API',
});

// Challenge endpoint
app.get('/siwa/challenge', async (req, res) => {
  const challenge = await siwa.createChallenge(req.query.pubkey);
  res.json(challenge);
});

// Verify endpoint
app.post('/siwa/verify', async (req, res) => {
  const session = await siwa.verifySignature(
    req.body.message, req.body.pubkey, req.body.signature
  );
  res.json(session);
});

// Protected route with middleware
app.get('/api/data', siwa.middleware(), (req, res) => {
  res.json({ agent: req.agentAddress });
});
import { Keypair } from '@solana/web3.js';
import { createMessage, serializeMessage, verify } from '@siwa/core';
import nacl from 'tweetnacl';
import bs58 from 'bs58';

// === AGENT SIDE ===

const keypair = Keypair.generate();
const pubkey = keypair.publicKey.toBase58();

// 1. Get challenge from service (fetch omitted for clarity)
const challenge = await getChallenge(pubkey);

// 2. Sign the challenge message
const msgBytes = new TextEncoder().encode(challenge.message);
const sig = nacl.sign.detached(msgBytes, keypair.secretKey);
const signature = bs58.encode(sig);

// === SERVICE SIDE ===

// 3. Verify the signature
const result = await verify(challenge.message, signature, pubkey, {
  domain: 'api.example.com',
});

if (result.success) {
  console.log('✓ Agent authenticated:', result.message.address);
  // Issue session token, grant access...
}
Features

Production-ready primitives.

Everything you need to add agent auth to your service. Nothing you don't.

🔐

Ed25519 Signatures

Same curve as Solana transactions. Agents prove identity with their existing keypair.

🔄

Replay Protection

One-time nonces and expiring challenges prevent signature reuse attacks.

⏱️

Time-Bounded

Challenges expire in minutes, sessions in hours. Configurable per service.

🧩

Express Middleware

One-line middleware for protected routes. Required or optional auth modes.

🗄️

Pluggable Stores

In-memory by default. Swap in Redis, Postgres, or any custom backend.

📋

Scoped Access

Resources field lets services define fine-grained permissions per session.

🔍

Domain Binding

Messages are bound to a specific domain, preventing cross-service replay.

📐

TypeScript-First

Full type definitions, zero any. IntelliSense works out of the box.

Packages

Modular by design.

Use just what you need — core for verification, client for agents, server for services.

@siwa/core

Message creation, parsing, serialization, and signature verification. The protocol itself.

npm i @siwa/core
@siwa/client

Drop-in SDK for AI agents. Sign challenges, manage sessions, authenticated fetch.

npm i @siwa/client
@siwa/server

Server utilities. Challenge generation, session management, Express middleware.

npm i @siwa/server
Use Cases

Where agents need identity.

🤖

Agent → Service Auth

AI agents authenticate with APIs, databases, and cloud services without human-provisioned credentials.

🔗

Multi-Agent Systems

Agents verify each other's identity before sharing data or delegating tasks in swarm architectures.

💰

DeFi for Agents

Trading bots and treasury agents authenticate with DeFi protocols using their existing Solana keypair.

📡

Agent Registries

Directories and marketplaces verify agent identity. Agents register themselves, no admin needed.

🏪

Agentic Commerce

Agents purchase services, reserve resources, or pay per API call — all authenticated by wallet.

🛡️

Access Control

Gate features by wallet address. Allowlist specific agents, enforce on-chain reputation, or check NFT holdings.

SIWA + x402 = Paid APIs

Authenticated micropayments. Agents pay per call with USDC. One flow: auth + payment.

// Premium endpoint with SIWA auth + x402 payment
app.get('/api/premium',
siwa.middleware(), // Auth first
x402({ treasury, price: 0.001 }), // Then payment
(req, res) => res.json({ data: 'premium' })
);
🔐
Auth + Pay
One wallet, one flow
💵
USDC Native
Stable, predictable pricing
Per-Call Billing
No subscriptions needed

Start authenticating agents.

Open source, MIT licensed, and ready for production. Add agent auth to your service in minutes.

View on GitHub See the code →