← Back to Docs

Code Examples

Complete working examples for Agent Passport authentication in Python, TypeScript, and Rust.

🐍

Python

Installation

bash
pip install pynacl base58 requests

Complete Agent Auth Client

python
"""
NervePay Agent Passport Authentication Client
Complete example for authenticating API requests with Ed25519 signatures.
"""
import nacl.signing
import base64
import base58
import time
import uuid
import requests
from typing import Optional, Dict, Any
class AgentPassport:
"""Client for authenticating API requests using Agent Passport."""
def __init__(self, agent_did: str, private_key_base58: str, base_url: str = "https://api.nervepay.xyz"):
"""
Initialize the Agent Passport client.
Args:
agent_did: Your agent's DID (e.g., "did:nervepay:agent:7xKp...")
private_key_base58: Base58-encoded Ed25519 private key (64 bytes)
base_url: NervePay API base URL
"""
self.agent_did = agent_did
self.base_url = base_url
# Decode the base58 private key
key_bytes = base58.b58decode(private_key_base58)
# Use first 32 bytes as seed to create signing key
self.signing_key = nacl.signing.SigningKey(key_bytes[:32])
def _create_signature(self, method: str, path: str, nonce: str, timestamp: str) -> str:
"""Create Ed25519 signature for the request."""
# Canonical payload format
payload = f"{method}\n{path}\n{nonce}\n{timestamp}\n{self.agent_did}"
# Sign the payload
signed = self.signing_key.sign(payload.encode())
signature_b64 = base64.b64encode(signed.signature).decode()
return f"ed25519:{signature_b64}"
def get_auth_headers(self, method: str, path: str) -> Dict[str, str]:
"""
Generate authentication headers for a request.
Args:
method: HTTP method (GET, POST, etc.)
path: Request path (e.g., "/api/data")
Returns:
Dictionary of authentication headers
"""
nonce = str(uuid.uuid4())
timestamp = str(int(time.time()))
signature = self._create_signature(method, path, nonce, timestamp)
return {
"Agent-DID": self.agent_did,
"X-Agent-Signature": signature,
"X-Agent-Nonce": nonce,
"X-Signature-Timestamp": timestamp,
}
def request(
self,
method: str,
url: str,
headers: Optional[Dict[str, str]] = None,
**kwargs
) -> requests.Response:
"""
Make an authenticated request.
Args:
method: HTTP method
url: Full URL or path (if path, base_url is prepended)
headers: Additional headers to include
**kwargs: Additional arguments passed to requests
Returns:
Response object
"""
from urllib.parse import urlparse
# Handle relative paths
if not url.startswith("http"):
url = f"{self.base_url}{url}"
path = urlparse(url).path
# Merge auth headers with any provided headers
all_headers = self.get_auth_headers(method, path)
if headers:
all_headers.update(headers)
return requests.request(method, url, headers=all_headers, **kwargs)
def get(self, url: str, **kwargs) -> requests.Response:
"""Make authenticated GET request."""
return self.request("GET", url, **kwargs)
def post(self, url: str, **kwargs) -> requests.Response:
"""Make authenticated POST request."""
return self.request("POST", url, **kwargs)
def whoami(self) -> Dict[str, Any]:
"""Get current agent identity information."""
response = self.get("/v1/agent-identity/whoami")
response.raise_for_status()
return response.json()
def get_capabilities(self) -> Dict[str, Any]:
"""Get agent capabilities and limits."""
response = self.get("/v1/agent-identity/capabilities")
response.raise_for_status()
return response.json()
# Usage Example
if __name__ == "__main__":
# Initialize with your credentials
agent = AgentPassport(
agent_did="did:nervepay:agent:7xKpQm3...",
private_key_base58="your-private-key-base58"
)
# Check identity
identity = agent.whoami()
print(f"Agent: {identity['name']}")
print(f"DID: {identity['did']}")
print(f"Reputation: {identity['reputation_score']}")
# Make authenticated API calls
response = agent.get("https://api.example.com/protected-resource")
print(response.json())
📘

TypeScript

Installation

bash
npm install tweetnacl bs58 uuid

Complete Agent Auth Client

typescript
/**
* NervePay Agent Passport Authentication Client
* Complete example for authenticating API requests with Ed25519 signatures.
*/
import nacl from 'tweetnacl';
import bs58 from 'bs58';
import { v4 as uuidv4 } from 'uuid';
interface AuthHeaders {
'Agent-DID': string;
'X-Agent-Signature': string;
'X-Agent-Nonce': string;
'X-Signature-Timestamp': string;
}
interface AgentIdentity {
did: string;
name: string;
reputation_score: number;
public_key: string;
capabilities: Record<string, unknown>;
}
export class AgentPassport {
private agentDid: string;
private signingKey: Uint8Array;
private baseUrl: string;
/**
* Initialize the Agent Passport client.
* @param agentDid - Your agent's DID (e.g., "did:nervepay:agent:7xKp...")
* @param privateKeyBase58 - Base58-encoded Ed25519 private key (64 bytes)
* @param baseUrl - NervePay API base URL
*/
constructor(
agentDid: string,
privateKeyBase58: string,
baseUrl: string = 'https://api.nervepay.xyz'
) {
this.agentDid = agentDid;
this.baseUrl = baseUrl;
// Decode base58 private key (64 bytes: 32 seed + 32 public)
const keyBytes = bs58.decode(privateKeyBase58);
this.signingKey = keyBytes;
}
private createSignature(method: string, path: string, nonce: string, timestamp: string): string {
// Canonical payload format
const payload = `${method}\n${path}\n${nonce}\n${timestamp}\n${this.agentDid}`;
// Sign the payload
const message = new TextEncoder().encode(payload);
const signature = nacl.sign.detached(message, this.signingKey);
const signatureB64 = Buffer.from(signature).toString('base64');
return `ed25519:${signatureB64}`;
}
/**
* Generate authentication headers for a request.
*/
getAuthHeaders(method: string, path: string): AuthHeaders {
const nonce = uuidv4();
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = this.createSignature(method, path, nonce, timestamp);
return {
'Agent-DID': this.agentDid,
'X-Agent-Signature': signature,
'X-Agent-Nonce': nonce,
'X-Signature-Timestamp': timestamp,
};
}
/**
* Make an authenticated fetch request.
*/
async fetch(url: string, options: RequestInit = {}): Promise<Response> {
// Handle relative paths
const fullUrl = url.startsWith('http') ? url : `${this.baseUrl}${url}`;
const urlObj = new URL(fullUrl);
const method = options.method || 'GET';
const authHeaders = this.getAuthHeaders(method, urlObj.pathname);
return fetch(fullUrl, {
...options,
headers: {
...options.headers,
...authHeaders,
},
});
}
/**
* Get current agent identity information.
*/
async whoami(): Promise<AgentIdentity> {
const response = await this.fetch('/v1/agent-identity/whoami');
if (!response.ok) {
throw new Error(`Failed to get identity: ${response.status}`);
}
return response.json();
}
/**
* Get agent capabilities and limits.
*/
async getCapabilities(): Promise<Record<string, unknown>> {
const response = await this.fetch('/v1/agent-identity/capabilities');
if (!response.ok) {
throw new Error(`Failed to get capabilities: ${response.status}`);
}
return response.json();
}
}
// Usage Example
async function main() {
const agent = new AgentPassport(
'did:nervepay:agent:7xKpQm3...',
'your-private-key-base58'
);
// Check identity
const identity = await agent.whoami();
console.log(`Agent: ${identity.name}`);
console.log(`DID: ${identity.did}`);
console.log(`Reputation: ${identity.reputation_score}`);
// Make authenticated API calls
const response = await agent.fetch('https://api.example.com/protected-resource');
const data = await response.json();
console.log(data);
}
main().catch(console.error);
🦀

Rust

Cargo.toml

toml
[dependencies]
ed25519-dalek = "2.0"
bs58 = "0.5"
base64 = "0.21"
uuid = { version = "1.0", features = ["v4"] }
reqwest = { version = "0.11", features = ["json"] }
tokio = { version = "1.0", features = ["full"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

Complete Agent Auth Client

rust
//! NervePay Agent Passport Authentication Client
//! Complete example for authenticating API requests with Ed25519 signatures.
use ed25519_dalek::{Signature, Signer, SigningKey};
use reqwest::header::{HeaderMap, HeaderValue};
use serde::{Deserialize, Serialize};
use std::time::{SystemTime, UNIX_EPOCH};
use uuid::Uuid;
#[derive(Debug, Deserialize)]
pub struct AgentIdentity {
pub did: String,
pub name: String,
pub reputation_score: f64,
pub public_key: String,
}
pub struct AgentPassport {
agent_did: String,
signing_key: SigningKey,
base_url: String,
client: reqwest::Client,
}
impl AgentPassport {
/// Create a new Agent Passport client.
pub fn new(agent_did: &str, private_key_base58: &str, base_url: Option<&str>) -> Self {
// Decode base58 private key
let key_bytes = bs58::decode(private_key_base58)
.into_vec()
.expect("Invalid base58 key");
// Use first 32 bytes as seed
let seed: [u8; 32] = key_bytes[..32].try_into().expect("Key too short");
let signing_key = SigningKey::from_bytes(&seed);
Self {
agent_did: agent_did.to_string(),
signing_key,
base_url: base_url.unwrap_or("https://api.nervepay.xyz").to_string(),
client: reqwest::Client::new(),
}
}
/// Create Ed25519 signature for the request.
fn create_signature(&self, method: &str, path: &str, nonce: &str, timestamp: &str) -> String {
let payload = format!(
"{}\n{}\n{}\n{}\n{}",
method, path, nonce, timestamp, self.agent_did
);
let signature: Signature = self.signing_key.sign(payload.as_bytes());
let signature_b64 = base64::encode(signature.to_bytes());
format!("ed25519:{}", signature_b64)
}
/// Generate authentication headers for a request.
pub fn get_auth_headers(&self, method: &str, path: &str) -> HeaderMap {
let nonce = Uuid::new_v4().to_string();
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs()
.to_string();
let signature = self.create_signature(method, path, &nonce, &timestamp);
let mut headers = HeaderMap::new();
headers.insert("Agent-DID", HeaderValue::from_str(&self.agent_did).unwrap());
headers.insert("X-Agent-Signature", HeaderValue::from_str(&signature).unwrap());
headers.insert("X-Agent-Nonce", HeaderValue::from_str(&nonce).unwrap());
headers.insert("X-Signature-Timestamp", HeaderValue::from_str(&timestamp).unwrap());
headers
}
/// Make an authenticated GET request.
pub async fn get(&self, path: &str) -> reqwest::Result<reqwest::Response> {
let url = format!("{}{}", self.base_url, path);
let headers = self.get_auth_headers("GET", path);
self.client.get(&url).headers(headers).send().await
}
/// Make an authenticated POST request.
pub async fn post<T: Serialize>(&self, path: &str, body: &T) -> reqwest::Result<reqwest::Response> {
let url = format!("{}{}", self.base_url, path);
let headers = self.get_auth_headers("POST", path);
self.client.post(&url).headers(headers).json(body).send().await
}
/// Get current agent identity information.
pub async fn whoami(&self) -> reqwest::Result<AgentIdentity> {
self.get("/v1/agent-identity/whoami")
.await?
.json()
.await
}
}
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let agent = AgentPassport::new(
"did:nervepay:agent:7xKpQm3...",
"your-private-key-base58",
None,
);
// Check identity
let identity = agent.whoami().await?;
println!("Agent: {}", identity.name);
println!("DID: {}", identity.did);
println!("Reputation: {}", identity.reputation_score);
Ok(())
}
💻

cURL

For quick testing, you can manually construct authenticated requests using cURL. Note: You'll need to generate the signature separately using a script.

Example Request

bash
# Set your credentials
export AGENT_DID="did:nervepay:agent:7xKpQm3..."
export NONCE=$(uuidgen | tr '[:upper:]' '[:lower:]')
export TIMESTAMP=$(date +%s)
# Generate signature (you need to compute this with your private key)
# See Python/TypeScript examples for signature generation
export SIGNATURE="ed25519:YOUR_SIGNATURE_HERE"
# Make authenticated request
curl -X GET "https://api.nervepay.xyz/v1/agent-identity/whoami" \
-H "Agent-DID: $AGENT_DID" \
-H "X-Agent-Signature: $SIGNATURE" \
-H "X-Agent-Nonce: $NONCE" \
-H "X-Signature-Timestamp: $TIMESTAMP"

Response Example

json
{
"did": "did:nervepay:agent:7xKpQm3...",
"name": "My AI Agent",
"reputation_score": 85.5,
"public_key": "ed25519:abc123...",
"capabilities": {
"max_transaction_amount": 100.00,
"allowed_operations": ["read", "write"]
},
"created_at": "2024-01-15T10:30:00Z"
}

Use Case Examples

Agent-to-Agent Authentication

Agents can authenticate with each other in multi-agent systems using their passports.

Learn more

API Protection

Verify agent identity before granting access to protected resources. Full server-side verification example included.

View code

Sign in with NerveSoon

OAuth-like flow for agents to authenticate with third-party services. Includes UI and headless flows.

Integration guide

Enterprise Governance

Audit all agent actions, enforce transaction limits, and meet compliance requirements.

Overview

Next Steps