Anonymous API Credits: A Web Platform Proposal

GitHub View on GitHub
Design Proposal

Disclaimer: This is a personal proposal and does not represent the views of my employer, Google.

Objective

Add browser-native support for anonymous, paid API usage through a new Web Platform API.

TL;DR: This proposal introduces a new Web API (navigator.anonymousCredits) that enables browsers to purchase and spend anonymous API credits. By embedding the cryptographic operations directly in the browser, we can prevent side-channel attacks and provide stronger privacy guarantees for users accessing APIs like LLMs, while maintaining security for API providers. Further, the anonymous credit APIs can be used by AI agents to privately access content which is, for humans, funded via ads.

Background: The Problem

In today's web ecosystem:

This creates significant privacy concerns, especially for sensitive applications:

Security Concern: Implementing cryptographic primitives in JavaScript is vulnerable to side-channel attacks. For strong security guarantees, these operations must be implemented directly in the browser as a native Web API, similar to approaches like the Private Proof API and WebCrypto.

Key Requirements

The Anonymous Credits Web API

requestData Web API

The Anonymous Credits API would be available via navigator.anonymousCredits and follows similar permission and security patterns as the Private Proof API and other sensitive browser APIs.

API Interface

interface AnonymousCredits {
  
  // Purchase credits and get initial token
  Promise<Response> purchaseCredits(PurchaseOptions options);
  
  // Spend credits anonymously
  Promise<Response> spendCredits(SpendOptions options);
    
  // Clear all credit tokens
  Promise<void> clearAllTokens();
  
  // Clear tokens for a specific issuer
  Promise<void> clearTokens(string issuer);
}

interface PurchaseOptions {
  required string endpoint;          // Origin of the issuer 
  optional object requestData;       // Payment confirmation token
}

interface SpendOptions {
  required string endpoint;          // API endpoint to call
  required number amount;            // Amount to spend
  optional object requestData;       // Data to include in the request
}

Technical Implementation

Under the hood, the API uses anonymous credentials:

  1. KeyGen: The API provider (issuer) generates a keypair and publishes the public key at a well-known endpoint.
  2. Issue: When a user purchases credits:
    • The browser generates random blinding factors k and r internally
    • The browser handles the cryptographic request/response with the issuer
    • The resulting Credit Token is stored securely in the browser's protected storage
  3. Spend: When spending credits:
    • The browser selects an appropriate token (or uses the specified one)
    • Generates new random values internally for the next token
    • Creates and verifies zero-knowledge proofs entirely within the browser
    • Handles the API request with appropriate anonymous credentials
    • Processes the response and stores the new token with remaining balance
Side-Channel Prevention: By implementing these operations natively in the browser:

Usage Example for Web Developers

// Permission is now handled via the Permissions-Policy header
// The browser will automatically prompt for permission on first API use
// This follows the same model as the Geolocation API

// Purchase credits from an API provider
async function buyCredits(amount) {
  try {
    const purchaseResponse = await navigator.anonymousCredits.purchaseCredits({
      endpoint: "https://api-provider.com",
      amount: amount,
      requestData: { "confirmation": "payment-confirmation-xyz"}, // From payment processor
    });
    
    console.log(`Purchased ${amount} credits`);
    return;
  } catch (error) {
    console.error("Failed to purchase credits:", error);
    throw error;
  }
}

// Call an API anonymously using credits
async function queryLLMAnonymously(prompt) {
  try {
    // Spend 10 credits to query the LLM API
    const result = await navigator.anonymousCredits.spendCredits({
      endpoint: "https://api-provider.com/v1/completions",
      amount: 10,
      requestData: {
        model: "gpt-4",
        prompt: prompt,
        max_tokens: 1000
      }
    });
    
    // Get the API response
    const data = await result.response.json();
    
    return data.completion;
  } catch (error) {
    console.error("Anonymous API call failed:", error);
    throw error;
  }
}

Security and Privacy Considerations

Permission Model

The Anonymous Credits API uses a permission policy controlled via HTTP headers:

Permissions-Policy: anoncreds=*
        

This header can be used to control which origins are allowed to use the Anonymous Credits API, similar to the Geolocation API. The default value is *, which allows all origins to use the API.

Additionally, the API requires explicit user permission:

Browser Storage

Credit tokens are stored securely:

Anti-Fingerprinting Measures

To prevent using this API for fingerprinting:

Implementation with Anonymous Credentials

The underlying cryptographic implementation uses anonymlous credentials, which enable selective disclosure and zero-knowledge proofs:

Cryptographic Components

Comparison to Private Proof API

Private Proof API

  • ✅ Provides privacy-preserving verification
  • ✅ Browser-native implementation
  • ✅ Focused on preventing abuse while preserving privacy
  • ✅ Uses zero-knowledge proofs
  • ✅ Underlying tokens are reused
  • ✅ Does not require user permission to use the API
  • ❌ Not designed for payment/credits systems

Anonymous Credits API

  • ✅ Specifically designed for API payment credits
  • ✅ Full anonymity across transactions
  • ✅ Supports partial spending of credits
  • ✅ Double-spend protection
  • ✅ Similar zero-knowledge proofs
  • ✅ Underlying tokens are not reused, but a new one is created with the remaining balance
  • ❌ Requires user permission to use the API

Anonymous Credits HTTP API

In addition to the JavaScript API, this proposal includes a standardized header-based HTTP API to enable interoperability between browser implementations and API providers.

HTTP Headers and Endpoints

Permission Policy

Websites can control which origins are allowed to use the Anonymous Credits API using the Permissions-Policy header:

Permissions-Policy: anoncreds=*                   # Allow all origins (default)
Permissions-Policy: anoncreds=(self)              # Allow only same origin
Permissions-Policy: anoncreds=(self "https://trusted-third-party.com")  # Allow specific origins
            

This works similarly to other permission-policy controlled features like the Geolocation API.

Well-Known Public Key Endpoint

API providers must publish their public key at a well-known location:

GET /.well-known/anonymous-credits

Response:
{
  "version": "1.0",
  "issuer": "https://api-provider.com",
  "publicKey": "BASE64_ENCODED_PUBLIC_KEY",
}
            

Credit Issuance

When a client purchases credits, the following exchange occurs:

POST /api/anonymous-credits/token

Headers:
X-Anonymous-Credits-Version: 1.0
X-Anonymous-Credits-Operation: issue
X-Anonymous-Credits-Amount: 100

Request Body:
{
  "type": "credit-token-request",
  "request": "BASE64_ENCODED_REQUEST_DATA",
  "paymentToken": "PAYMENT_PROVIDER_TOKEN"
}

Response:
{
  "type": "credit-token-issuance",
  "issuance": "BASE64_ENCODED_ISSUANCE_DATA",
}
            

The request field contains the client's blinded values (k, r) needed for the authentication code. The issuance response contains the data needed to construct a valid Credit Token.

Credit Spending

When calling an API using anonymous credits:

POST /api/service/endpoint

Headers:
X-Anonymous-Credits-Version: 1.0
X-Anonymous-Credits-Operation: spend
X-Anonymous-Credits-Amount: 10
X-Anonymous-Credits-Proof: BASE64_ENCODED_PROOF_DATA

Response Headers:
X-Anonymous-Credits-Status: success
X-Anonymous-Credits-Refund: BASE64_ENCODED_REFUND_DATA

Response Body:
{
  "data": "REQUESTED_API_SERVICE_DATA"
}
            

The X-Anonymous-Credits-Proof header contains:

The X-Anonymous-Credits-Refund header contains the authentication code needed to construct a new Credit Token with the remaining balance.

Security Aspects

Double-Spend Prevention

The API implements double-spend prevention through:

Since k is a random value generated by the client and not linked to their identity, revealing it does not compromise anonymity.

Transaction Unlinkability

Each time credits are spent:

Error Handling

API errors follow a standardized format:

HTTP Status: 4xx or 5xx

{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message"
  }
}
        

Common error codes include invalid_proof, double_spend, insufficient_credits, and rate_limit_exceeded.

Server Side Considerations

When implementing the Anonymous Credits HTTP API:

Client Side Considerations

Next Steps: Feedback is very important to this proposal going anywhere, please reply on my GitHub repository here: discussion