VoidnetVoid Docs
MCP

MCP OAuth (Preview)

OAuth 2.0 authorization server — access tokens, grant types, and endpoints.

In preview — OAuth login flows are still stabilizing. API keys work everywhere OAuth does; prefer keys unless you need short-lived scoped tokens.

The Voidnet acts as an OAuth 2.0 authorization server, issuing JWT access tokens for production systems.

Token types

JWT access tokens

Access tokens are JSON Web Tokens (JWTs) signed with RS256. They are three base64url-encoded segments separated by dots:

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.signature

Each token contains:

  • sub — Buyer UUID
  • scope — Permission scope (mcp:tools for tool calls, llm:completions for chat completions)
  • exp — Expiration time (default 1 hour)
  • iat — Issued at time
  • iss — Voidnet issuer URL
  • aud — Voidnet issuer URL (fixed at mint time; no client-controlled audience input)
  • kid — Key ID identifying the signing key in the JWKS

API keys

The Voidnet also accepts API keys (vnb-sk-*) as a simpler alternative. See the Buyer Guide for API key management.

Grant types

client_credentials

Exchange your API key for a short-lived JWT:

curl -X POST http://localhost:8090/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_id=vnb-sk-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6"

Successful response:

{
  "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "mcp:tools"
}

The returned access_token is a JWT usable in any Authorization: Bearer header.

Notes:

  • No separate client_secret is needed — the API key itself is the secret
  • An optional scope parameter is accepted (mcp:tools default, llm:completions for chat)
  • The aud claim is always the Voidnet issuer URL — the token endpoint accepts no client-controlled audience input

authorization_code (+ PKCE, interactive clients)

For OAuth-aware MCP clients (Claude Desktop, Cursor, VS Code). The gateway hosts the login+consent page — no redirect to any accounts app:

  1. Open GET /authorize?client_id=<key>&redirect_uri=<exact-callback>&response_type=code&code_challenge=<43-char-base64url>&code_challenge_method=S256&scope=mcp:tools&state=<opaque> — renders the login+consent form.
  2. User submits email+password via POST /authorize — issues a single-use authorization code (5-minute TTL) and redirects to redirect_uri?code=...&state=....
  3. Exchange the code at POST /oauth/token (grant_type=authorization_code, plus code, redirect_uri, code_verifier) — returns access token and refresh token.

PKCE S256 is mandatory; redirect_uri must be an exact http(s) match.

refresh_token

Refresh tokens live 30 days and rotate on every use (single-use — reuse is rejected):

curl -X POST http://localhost:8090/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=refresh_token" \
  -d "client_id=vnb-sk-a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6" \
  -d "refresh_token=<previous-refresh-token>"

The response contains a new access token and a new refresh token — store both, discard the old refresh token.

Using tokens

All requests to the Voidnet use the Authorization: Bearer header:

# API key (local gateway on 8090, prod on 8080 / api.openvoidnet.com)
curl -X POST http://localhost:8090/v1-beta/mcp/acmecorp/weather-tools \
  -H "Authorization: Bearer vnb-sk-..." \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: tools/list" \
  -H "Mcp-Name: tools/list" \
  -d '{"jsonrpc": "2.0", "id": "1", "method": "tools/list"}'

# JWT access token
TOKEN="eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9..."
curl -X POST http://localhost:8090/v1-beta/mcp/acmecorp/weather-tools \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -H "MCP-Protocol-Version: 2026-07-28" \
  -H "Mcp-Method: tools/list" \
  -H "Mcp-Name: tools/list" \
  -d '{"jsonrpc": "2.0", "id": "1", "method": "tools/list"}'

Every billable routed call carries X-Voidnet-Request-Id downstream to the publisher and upstream to the buyer. Match that value to console Usage Logs requestId to reconcile call by call. Non-billable discovery and list calls, including cache-served lists, carry no metering row.

The Voidnet auto-detects the credential type — three dot-separated segments means JWT, otherwise API key.

Token expiration

Tokens have an exp claim. When a token expires, the Voidnet returns api_key_expired (401):

  1. Detect the 401 response
  2. Request a new token from POST /oauth/token
  3. Retry the request with the new token

Publisher authentication

When the Voidnet proxies a request to a publisher's server, it authenticates using the publisher's API key (vnp-sk-*):

Authorization: Bearer vnp-sk-27fc6268dc64a9ba2c4cb92489e9175cbf404e260beb268b976f1a56582eff3

Publisher keys are:

  • Generated in the Console when publishing an app
  • The Voidnet always sends vnp-sk-* regardless of how the buyer authenticated
  • Sent to the publisher server on every proxied request

OAuth endpoints

The Voidnet acts as an OAuth 2.0 authorization server. Full interactive reference (parameters, responses, Try-it) lives on the generated MCP API page:

EndpointDescription
POST /oauth/tokenIssue access tokens (client_credentials, authorization_code, refresh_token)
GET /authorizeRender the login+consent form (interactive clients)
POST /authorizeProcess login+consent, issue authorization code, redirect
GET /.well-known/oauth-authorization-serverRFC 8414 AS metadata
GET /.well-known/oauth-protected-resourceRFC 9728 resource metadata
GET /.well-known/jwks.jsonVoidnet's public signing keys

Credential management

API keys are managed through the Voidnet:

  • Generate — Create a new key from the API Keys section
  • Revoke — Immediately invalidate a compromised key
  • Rotate — Generate a new key, update your configuration, revoke the old one

OAuth access tokens are obtained programmatically:

  • client_credentials — Exchange an API key for a JWT at POST /oauth/token
  • Tokens expire after a configurable period (default 1 hour)

Credential security best practices

  • Store API keys and tokens in environment variables, not in code
  • Use a secrets manager in production
  • Rotate API keys periodically
  • Revoke compromised keys immediately
  • Never expose credentials in client-side code, logs, or version control
  • Use short-lived JWT access tokens in production systems instead of raw API keys

On this page