🚧

Coming Soon

Sign in with Nerve is under development. Preview the planned functionality below.

← Back to Docs

Sign in with NerveComing Soon

OAuth-like authentication for AI agents. Enable your platform to verify agent identities with cryptographic proof.

The OAuth of AI Agents

"Sign in with Nerve" lets AI agents authenticate with your service using their cryptographic identity. No passwords, no API keys - just Ed25519 signatures and W3C DIDs.

UI flow for web apps
Server-side flow for headless agents
Portable agent identity

Two Authentication Flows

UI Flow (OAuth-like)

For web applications where users interact via browser. Redirects to NervePay for agent selection, then back with an auth code.

  • 1.User clicks "Sign in with Nerve" button
  • 2.Redirect to NervePay authorize page
  • 3.User selects agent identity
  • 4.Redirect back with authorization code
  • 5.Exchange code for access token

Server Flow (Headless)

For AI agents authenticating programmatically without a UI. Uses Ed25519 signatures to prove identity.

  • 1.Request authentication challenge
  • 2.Agent signs challenge with private key
  • 3.Submit signed challenge
  • 4.Receive access token

Button Component

React / Next.js

import { SignInWithNerve } from '@nervepay/react';

function LoginPage() {
  return (
    <SignInWithNerve
      clientId="your-app.com"
      redirectUri="https://your-app.com/auth/callback"
      scope="identity"
    />
  );
}

UI Flow Implementation

1. Add the Button

Add the "Sign in with Nerve" button to your login page:

<!-- HTML/JavaScript -->
<a href="https://nervepay.xyz/auth/nerve/authorize?
  client_id=your-app.com&
  redirect_uri=https://your-app.com/callback&
  scope=identity&
  response_type=code&
  state=random-csrf-token"
  class="nerve-button">
  Sign in with Nerve
</a>

2. Handle the Callback

When the user authorizes, they'll be redirected to your callback URL with a code:

// Your callback endpoint receives:
// GET /callback?code=abc123&state=random-csrf-token

// Verify state matches what you sent
if (state !== storedState) throw new Error('CSRF detected');

// Exchange code for token
const response = await fetch('https://api.nervepay.xyz/v1/oauth/token', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    grant_type: 'authorization_code',
    code: code,
    redirect_uri: 'https://your-app.com/callback',
    client_id: 'your-app.com',
  }),
});

const { access_token, agent_did, agent_name, reputation_score } = await response.json();

3. Verify the Token (Optional)

For additional security, verify the token with NervePay:

const verifyResponse = await fetch('https://api.nervepay.xyz/v1/oauth/verify', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ access_token }),
});

const {
  valid,
  agent_did,
  agent_name,
  public_key,
  reputation_score,
  capabilities,
} = await verifyResponse.json();

if (valid) {
  // Agent is authenticated! Create session, etc.
}

Server Flow Implementation (Headless)

Use this flow when an AI agent needs to authenticate programmatically without user interaction. The agent proves its identity by signing a challenge with its Ed25519 private key.

1. Request Challenge

# Request a challenge for the agent to sign
curl -X POST https://api.nervepay.xyz/v1/oauth/challenge \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "your-app.com",
    "agent_did": "did:nervepay:agent:abc123...",
    "scope": "identity"
  }'

# Response:
{
  "challenge": "{"challenge_id":"...","agent_did":"...","nonce":"..."}",
  "challenge_id": "uuid",
  "expires_at": "2026-02-03T12:05:00Z",
  "message": "Sign this challenge..."
}

2. Agent Signs Challenge

import nacl from 'tweetnacl';
import { Buffer } from 'buffer';

// Agent's private key (Ed25519, 64 bytes base58)
const privateKey = bs58.decode(process.env.AGENT_PRIVATE_KEY);

// Sign the challenge
const message = Buffer.from(challenge);
const signature = nacl.sign.detached(message, privateKey);
const signatureBase64 = Buffer.from(signature).toString('base64');

3. Authenticate with Signature

curl -X POST https://api.nervepay.xyz/v1/oauth/authenticate \
  -H "Content-Type: application/json" \
  -d '{
    "challenge_id": "uuid-from-step-1",
    "agent_did": "did:nervepay:agent:abc123...",
    "signature": "base64-encoded-signature"
  }'

# Response:
{
  "access_token": "eyJ...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "agent_did": "did:nervepay:agent:abc123...",
  "agent_name": "My Agent",
  "reputation_score": 85.5,
  "scope": "identity",
  "public_key": "ed25519:..."
}

Complete Python Example

import requests
import nacl.signing
import base64
import base58

class NerveAuth:
    """Authenticate an AI agent with NervePay using Sign in with Nerve."""

    def __init__(self, agent_did: str, private_key_base58: str):
        self.agent_did = agent_did
        self.private_key = base58.b58decode(private_key_base58)
        self.base_url = "https://api.nervepay.xyz"

    def authenticate(self, client_id: str) -> dict:
        """Authenticate and get access token."""

        # Step 1: Request challenge
        challenge_resp = requests.post(
            f"{self.base_url}/v1/oauth/challenge",
            json={
                "client_id": client_id,
                "agent_did": self.agent_did,
                "scope": "identity"
            }
        )
        challenge_data = challenge_resp.json()

        # Step 2: Sign challenge
        signing_key = nacl.signing.SigningKey(self.private_key[:32])
        signature = signing_key.sign(challenge_data["challenge"].encode())
        signature_b64 = base64.b64encode(signature.signature).decode()

        # Step 3: Authenticate
        auth_resp = requests.post(
            f"{self.base_url}/v1/oauth/authenticate",
            json={
                "challenge_id": challenge_data["challenge_id"],
                "agent_did": self.agent_did,
                "signature": signature_b64
            }
        )

        return auth_resp.json()


# Usage
auth = NerveAuth(
    agent_did="did:nervepay:agent:abc123...",
    private_key_base58="your-private-key-base58"
)

token_data = auth.authenticate(client_id="your-app.com")
print(f"Access Token: {token_data['access_token']}")
print(f"Agent: {token_data['agent_name']} (rep: {token_data['reputation_score']})")

API Reference

GET /auth/nerve/authorize

OAuth authorize page (UI flow). Redirects user to select agent identity.

ParameterRequiredDescription
client_idYesYour application identifier
redirect_uriYesWhere to redirect after auth
scopeNoRequested permissions (default: identity)
stateNoCSRF protection token
POST /v1/oauth/token

Exchange authorization code for access token.

POST /v1/oauth/challenge

Request authentication challenge (server-side flow).

POST /v1/oauth/authenticate

Submit signed challenge to get access token (server-side flow).

POST /v1/oauth/verify

Verify an access token and get agent information.