Objective
Add browser-native support for anonymous, paid API usage through a new Web Platform 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:
- API providers sell access to their services via API credits
- Users create API keys tied to their identity
- Each API call includes the same API key in request headers
- This reveals user identity and allows all activities to be linked together
This creates significant privacy concerns, especially for sensitive applications:
- When using Large Language Models (LLMs), users may share personal or sensitive information
- Web browsers and applications may inadvertently leak user context across API calls
- LLM-based agents representing users need anonymity when accessing multiple services
Key Requirements
- Browser-native implementation: Cryptographic operations must be handled by the browser to prevent side-channel attacks
- Prevent double-spending: API providers must be confident that credits cannot be spent more than once
- Credit conservation: The total number of credits issued must always be greater than or equal to the quantity of credits spent
- True anonymity: API providers should be unable to correlate different spending transactions to the same user
- User control: Users must be able to view, manage, and clear their anonymous credentials
- Permission-based: Access to the API requires explicit user permission
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:
- KeyGen: The API provider (issuer) generates a keypair and publishes the public key at a well-known endpoint.
- 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
- 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
- Cryptographic computations happen in the browser's secure context
- Random values are generated using the browser's secure random number generator
- Timing attacks are mitigated through constant-time implementations
- Memory access patterns are protected from JavaScript observation
- Private keys and tokens never leave the browser's secure storage
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:
- Permission prompt clearly explains what the API does and how it will be used
- Permission can be revoked via browser settings
- Limited to secure contexts (HTTPS only)
- Follows the same permission model as other sensitive APIs
Browser Storage
Credit tokens are stored securely:
- Protected from JavaScript access (cannot be extracted via client-side code)
- Isolated per origin (tokens from one site cannot be used by another)
- Unpartitioned in third party contexts, to enable embedded micropayment providers
- Cleared when browser data is cleared
- Optionally, support for user-triggered clearing via browser UI
Anti-Fingerprinting Measures
To prevent using this API for fingerprinting:
- Tokens are not exposed to JavaScript directly, instead an opaque ID is exposed
- Timing of cryptographic operations is constant
- API returns standardized errors that don't leak information
- Spends have standardized formats that don't reveal browser-specific details or any information about their contents
- Balance amounts must be obscured from the renderer
Implementation with Anonymous Credentials
The underlying cryptographic implementation uses anonymlous credentials, which enable selective disclosure and zero-knowledge proofs:
Cryptographic Components
- Issuer Setup: Generate keypair (sk, pk)
- Credit Issuance: Authenticate a tuple of (n, k, r) where:
- n = number of credits (visible to issuer)
- k = random identifier (hidden from issuer, prevents double-spending)
- r = random value (hidden from issuer, provides unlinkability)
- Credit Spending: Uses zero-knowledge proofs to:
- Prove possession of an authenticated (n, k, r)
- Prove that n ≥ c (where c is the amount being spent)
- Reveal only k (for double-spend prevention) and c
- Create a commitment to new values (n-c, k', r') for the remaining balance
- Issuer signs that commitment without being able to know its contents, retrieving a new authentication code with a new k' which cannot be re-identified in future spends
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 revealed k value (for double-spend prevention)
- Zero-knowledge proof of a valid authentication code on (n, k, r)
- Proof that n ≥ c (where c is the amount being spent)
- Commitment to new values (n-c, k', r') for the remaining balance
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:
- Requiring the client to reveal the k value when spending credits
- Server maintaining a database of spent k values
- Rejecting any proof that attempts to reuse a previously revealed k value
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:
- The client generates new random values k' and r'
- The old token is consumed and a new token is issued with remaining balance
- There is no way for the server to link the new token to previous transactions
- Even if the server colludes with payment providers, spent credits remain anonymous
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:
- All cryptographic operations should be constant-time to prevent timing attacks
- The API should be served over HTTPS with strong TLS settings
Client Side Considerations
- Performance: Native implementation ensures efficient cryptographic operations
- Accessibility: Browser UI should make credit management accessible to all users
- Mobile Support: Mobile browsers should support the same API
- Internationalization: UI and error messages should be localized
- Audit Trail: Provide users with privacy-preserving usage history