Skip to main content
BioAgents supports three authentication methods: JWT authentication for external frontends, x402 for USDC micropayments on Base, and b402 for USDT micropayments on BNB Chain.

Authentication Methods

SettingOptionsPurpose
AUTH_MODEnone / jwtJWT authentication for external frontends
X402_ENABLEDtrue / falsex402 USDC micropayments on Base
B402_ENABLEDtrue / falseb402 USDT micropayments on BNB Chain
Authentication methods are independent and can be combined. Payment authentication (x402/b402) takes priority over JWT.

JWT Authentication

For external frontends connecting to the API. Your backend authenticates users and signs JWTs with a shared secret.

Quick Start

1

Generate Secret

Generate a secure random secret:
openssl rand -hex 32
2

Configure Environment

AUTH_MODE=jwt
BIOAGENTS_SECRET=your-secure-secret-here
MAX_JWT_EXPIRATION=3600  # Optional: 1 hour max
3

Sign JWTs in Your Backend

See code examples below for signing JWTs in your backend.
4

Call API with JWT

Include the JWT in the Authorization header:
curl -X POST https://your-api.com/api/chat \
  -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"message": "What is rapamycin?"}'

How JWT Auth Works

JWT Payload Requirements

The JWT payload must include the following claims:
sub
string
required
User ID as a valid UUID. This identifies the user in the database.
Must be a valid UUID format. Generate with crypto.randomUUID() or equivalent.
exp
number
required
Expiration timestamp (Unix epoch time).Maximum expiration is controlled by MAX_JWT_EXPIRATION (default: 3600 seconds).
iat
number
required
Issued at timestamp (Unix epoch time).
email
string
User email (optional).
orgId
string
Organization ID for multi-tenant deployments (optional).

Code Examples

import * as jose from 'jose';

const secret = new TextEncoder().encode(process.env.BIOAGENTS_SECRET);

const jwt = await new jose.SignJWT({
  sub: 'a1b2c3d4-e5f6-7890-abcd-ef1234567890'  // Must be UUID
})
  .setProtectedHeader({ alg: 'HS256' })
  .setIssuedAt()
  .setExpirationTime('1h')
  .sign(secret);

// Call BioAgents API
const response = await fetch('https://your-bioagents-api/api/chat', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${jwt}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({ message: 'What is rapamycin?' })
});

Important Notes

Never expose BIOAGENTS_SECRET - Generate JWTs server-side only. Never send the secret to the client.
Same user = same UUID - Use consistent UUIDs per user to maintain conversation history.
Use short expiration - 1 hour recommended, max configurable via MAX_JWT_EXPIRATION.

x402 Payment Protocol

Pay-per-request access using USDC micropayments on Base network.

Features

Gasless Transfers

EIP-3009 for fee-free USDC transfers

Embedded Wallets

Email-based wallet creation via CDP

HTTP 402 Flow

Standard “Payment Required” protocol

Base Network

Supports testnet (Base Sepolia) and mainnet

Configuration

1

Get Coinbase CDP Credentials

Get credentials from Coinbase Developer Portal:
CDP_API_KEY_ID=your_key_id
CDP_API_KEY_SECRET=your_key_secret
CDP_PROJECT_ID=your_project_id
2

Configure x402

X402_ENABLED=true
X402_PAYMENT_ADDRESS=0xYourWalletAddress
X402_ENVIRONMENT=testnet  # or 'mainnet'
X402_NETWORK=base-sepolia  # or 'base' for mainnet
X402_USDC_ADDRESS=0x036CbD53842c5426634e7929541eC2318f3dCF7e
3

Test Payment Flow

Use the x402 client library to test payments:
import { x402Fetch } from 'x402-fetch';

const response = await x402Fetch('http://localhost:3000/api/x402/chat', {
  method: 'POST',
  body: JSON.stringify({ message: 'What is DNA?' }),
  x402: {
    privateKey: process.env.WALLET_PRIVATE_KEY,
    network: 'base-sepolia'
  }
});

How x402 Works

x402 Environment Variables

X402_ENABLED
boolean
default:"false"
Enable x402 payment protocol.
X402_ENVIRONMENT
string
default:"testnet"
Environment: testnet (Base Sepolia) or mainnet (Base).
X402_PAYMENT_ADDRESS
string
required
Your wallet address (0x…) to receive payments.
X402_FACILITATOR_URL
string
default:"https://x402.org/facilitator"
x402 facilitator service URL.
X402_NETWORK
string
default:"base-sepolia"
Network: base-sepolia (testnet) or base (mainnet).
X402_ASSET
string
default:"USDC"
Payment asset (USDC).
X402_USDC_ADDRESS
string
default:"0x036CbD53842c5426634e7929541eC2318f3dCF7e"
USDC contract address (testnet default shown).
X402_TIMEOUT
number
default:"30"
Payment timeout in seconds.

Pricing

Default: $0.01 per request. Configure in src/x402/pricing.ts:
src/x402/pricing.ts
export const routePricing: RoutePricing[] = [
  {
    route: "/api/x402/chat",
    priceUSD: "0.01",
    description: "Chat API access",
  },
];

b402 Payment Protocol

Pay-per-request access using USDT micropayments on BNB Chain.

Configuration

B402_ENABLED=true
B402_ENVIRONMENT=testnet  # or 'mainnet'
B402_PAYMENT_ADDRESS=0xYourWalletAddress
B402_FACILITATOR_URL=https://facilitator.bioagents.dev
B402_NETWORK=bnb-testnet  # or 'bnb' for mainnet
B402_ASSET=USDT
B402_USDT_ADDRESS=0x337610d27c682E347C9cD60BD4b3b107C9d34dDd  # Testnet
B402_TIMEOUT=30
b402 works identically to x402 but uses USDT on BNB Chain instead of USDC on Base.

Authentication Priority

When multiple auth methods are available, the system uses this priority:
  1. x402/b402 payment proof - Cryptographic wallet signature (highest trust)
  2. JWT token - Verified signature
  3. Anonymous - Only if AUTH_MODE=none

Combining JWT + Payment Auth

You can enable both systems simultaneously:
AUTH_MODE=jwt
X402_ENABLED=true
This allows:
  • JWT-authenticated users to access /api/chat and /api/deep-research/* (no payment)
  • Anyone to pay-per-request via /api/x402/chat and /api/x402/deep-research/*

API Endpoints

EndpointAuth RequiredPayment Required
/api/chatJWT (if AUTH_MODE=jwt)No
/api/x402/chatNoYes (x402)
/api/b402/chatNoYes (b402)
/api/deep-research/startJWT (if AUTH_MODE=jwt)No
/api/deep-research/statusJWT (if AUTH_MODE=jwt)No
/api/x402/deep-research/startNoYes (x402)
/api/x402/deep-research/statusNoYes (x402)
/api/x402/configNoNo
/api/healthNoNo

Database Schema

Payment Tracking - x402_payments

CREATE TABLE x402_payments (
  id UUID PRIMARY KEY,
  user_id UUID REFERENCES users(id),
  conversation_id UUID REFERENCES conversations(id),
  message_id UUID REFERENCES messages(id),
  amount_usd NUMERIC NOT NULL,
  amount_wei TEXT NOT NULL,
  asset TEXT DEFAULT 'USDC',
  network TEXT NOT NULL,
  tools_used TEXT[],
  tx_hash TEXT,
  payment_status TEXT CHECK (payment_status IN ('pending', 'verified', 'settled', 'failed')),
  payment_header JSONB,
  payment_requirements JSONB,
  error_message TEXT,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  verified_at TIMESTAMPTZ,
  settled_at TIMESTAMPTZ
);

Implementation Files

FilePurpose
src/middleware/authResolver.tsUnified auth middleware
src/services/jwt.tsJWT verification
src/middleware/x402.tsPayment enforcement
src/x402/service.tsPayment verification
src/types/auth.tsAuth types

Troubleshooting

Symptom: 401 UnauthorizedSolutions:
  • Verify BIOAGENTS_SECRET matches on both sides
  • Check JWT expiration (max 1 hour by default)
  • Ensure sub claim is a valid UUID
  • Verify AUTH_MODE=jwt is set on server
Symptom: x402_payment_invalid errorSolutions:
  • Check USDC/USDT balance in wallet
  • Verify network configuration (testnet vs mainnet)
  • Ensure facilitator URL is correct
  • Check payment signature is valid
Symptom: 404 on /api/x402/* or /api/b402/* routesSolutions:
  • Verify X402_ENABLED=true or B402_ENABLED=true is set
  • Restart server after changing .env
  • Check server logs for initialization errors
Symptom: Database error about invalid UUIDSolutions:
  • Ensure sub claim is a valid UUID format
  • Use crypto.randomUUID() to generate UUIDs
  • Don’t use email addresses or usernames as sub

Resources

x402 Protocol

Learn about the x402 payment protocol

Coinbase CDP

Get Coinbase Developer Platform credentials

Base Network

Learn about Base network

EIP-3009

Transfer With Authorization standard

Next Steps

Environment Variables

View all configuration options

Storage

Configure S3 storage for file uploads

Build docs developers (and LLMs) love