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.signatureEach token contains:
sub— Buyer UUIDscope— Permission scope (mcp:toolsfor tool calls,llm:completionsfor chat completions)exp— Expiration time (default 1 hour)iat— Issued at timeiss— Voidnet issuer URLaud— 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_secretis needed — the API key itself is the secret - An optional
scopeparameter is accepted (mcp:toolsdefault,llm:completionsfor chat) - The
audclaim 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:
- 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. - User submits email+password via
POST /authorize— issues a single-use authorization code (5-minute TTL) and redirects toredirect_uri?code=...&state=.... - Exchange the code at
POST /oauth/token(grant_type=authorization_code, pluscode,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):
- Detect the
401response - Request a new token from
POST /oauth/token - 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-27fc6268dc64a9ba2c4cb92489e9175cbf404e260beb268b976f1a56582eff3Publisher 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:
| Endpoint | Description |
|---|---|
POST /oauth/token | Issue access tokens (client_credentials, authorization_code, refresh_token) |
GET /authorize | Render the login+consent form (interactive clients) |
POST /authorize | Process login+consent, issue authorization code, redirect |
GET /.well-known/oauth-authorization-server | RFC 8414 AS metadata |
GET /.well-known/oauth-protected-resource | RFC 9728 resource metadata |
GET /.well-known/jwks.json | Voidnet'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