# How Pi Web Manages API Keys: Secure Server-Side Storage and Retrieval

> Discover how Pi Web secures API keys server-side using Next.js API routes and the Pi SDK. Learn how credentials are never exposed to the client and automatically injected into requests.

- Repository: [Alex Yang/pi-web](https://github.com/agegr/pi-web)
- Tags: best-practices
- Published: 2026-07-30

---

**Pi Web manages API keys through secure Next.js API routes that store credentials server-side using the Pi SDK's AuthStorage layer, never exposing raw keys to the client while automatically injecting them into outbound provider requests.**

The `agegr/pi-web` repository implements a robust security architecture for handling sensitive provider credentials. Instead of storing API keys in browser storage or environment variables exposed to the frontend, the application leverages **AuthStorage** from the Pi SDK to persist keys in the user's local `~/.pi/agent` directory. This server-side approach ensures that authentication secrets remain inaccessible to client-side JavaScript while remaining available for backend request injection.

## Secure Storage with AuthStorage

Pi Web delegates all credential persistence to the Pi SDK's **AuthStorage** layer. When a user saves an API key, the system writes the encrypted value to the local filesystem at `~/.pi/agent`, keeping sensitive data entirely within the server environment. This design prevents accidental exposure through browser dev tools or cross-site scripting vulnerabilities, as raw keys never traverse the network to the frontend.

## API Route Implementation for Key Management

The core logic resides in `app/api/auth/api-key/[provider]/route.ts`, which implements a RESTful interface for credential lifecycle management. This dynamic route handles three distinct operations for each provider ID passed as a parameter.

### Retrieving Authentication Status (GET)

The **GET** method checks for the existence of a stored key without revealing its contents. It returns a status object such as `{ status: "has-key" }` or `{ status: "missing" }`, allowing the frontend to toggle UI states without handling sensitive material. This pattern ensures that even if the API response is intercepted, no secret credentials leak to unauthorized parties.

### Storing Provider Credentials (POST)

The **POST** handler accepts a JSON payload containing `{ apiKey: string }` and writes the value to **AuthStorage**. Internally, the route examines the provider's prompt configuration to determine whether to store the value as an `api-key` or `bearer-token` type, accommodating different authentication schemes across model providers like OpenAI, Google, or Anthropic.

```typescript
// Save a new API key for a specific provider
await fetch(`/api/auth/api-key/${encodeURIComponent(providerId)}`, {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ apiKey: "YOUR_KEY_HERE" })
});

```

### Revoking Access (DELETE)

The **DELETE** method permanently removes the stored credential from **AuthStorage**, effectively revoking the application's access to that provider. This operation is irreversible and requires the user to re-authenticate before subsequent API calls can succeed.

```typescript
// Delete a stored API key
await fetch(`/api/auth/api-key/${encodeURIComponent(providerId)}`, { 
  method: "DELETE" 
});

```

## Frontend Integration with ModelsConfig

The **ModelsConfig** component located at [`components/ModelsConfig.tsx`](https://github.com/agegr/pi-web/blob/main/components/ModelsConfig.tsx) (lines 1359-1384) serves as the primary interface for key management. This React component manages provider configuration UI and communicates with the API routes using standard fetch requests. When users input new credentials or click "Remove," the component dispatches the appropriate POST or DELETE requests to the dynamic routes, then refreshes the authentication status via GET requests to update the UI indicators.

```typescript
// Check if user has configured a key (returns status, not the key)
const status = await fetch(
  `/api/auth/api-key/${encodeURIComponent(providerId)}`
).then(r => r.json());
// Returns: { status: "has-key" } or { status: "missing" }

```

## Automatic Key Injection for Model Discovery

When Pi Web discovers available models from third-party providers, it automatically injects stored credentials into outgoing requests. The route at [`app/api/models-config/discover/route.ts`](https://github.com/agegr/pi-web/blob/main/app/api/models-config/discover/route.ts) (lines 23-26) intercepts model discovery calls and checks for missing authentication headers such as `x-api-key` or `x-goog-api-key`. If the request lacks these headers, the middleware retrieves the corresponding key from **AuthStorage** and appends it to the headers before forwarding the request to the provider's API.

This injection mechanism ensures that provider通信 remains authenticated without requiring manual header management in the frontend code, while maintaining zero exposure of secrets to the browser.

## Summary

- **Server-side storage**: API keys persist in the Pi SDK's **AuthStorage** at `~/.pi/agent`, never touching localStorage or cookies.
- **Status-only retrieval**: The GET endpoint at `app/api/auth/api-key/[provider]/route.ts` returns only presence indicators, never raw values.
- **Dynamic provider support**: The POST handler automatically selects between `api-key` and `bearer-token` storage types based on provider configuration.
- **Automatic injection**: The discovery route at [`app/api/models-config/discover/route.ts`](https://github.com/agegr/pi-web/blob/main/app/api/models-config/discover/route.ts) transparently adds stored keys to outbound provider requests when headers like `x-api-key` are missing.
- **Secure deletion**: DELETE requests permanently revoke credentials from **AuthStorage** without leaving residual data in browser memory.

## Frequently Asked Questions

### Where are API keys physically stored in Pi Web?

API keys are stored in the Pi SDK's **AuthStorage** layer, which writes encrypted files to the local `~/.pi/agent` directory on the server. This location is inaccessible to browser clients and requires server-side code execution to read or modify, providing a secure vault for sensitive credentials.

### Does Pi Web expose API keys to the browser?

No. According to the source code in `app/api/auth/api-key/[provider]/route.ts`, GET requests return only authentication status strings like `"has-key"` or `"missing"`. The raw API key values never leave the server environment, ensuring complete isolation from client-side JavaScript and network inspection tools.

### How does Pi Web handle different authentication types across providers?

The POST handler in the API key route inspects each provider's prompt configuration to determine the appropriate storage format. It automatically categorizes credentials as either `api-key` or `bearer-token` types, allowing the system to support diverse authentication schemes (API keys, JWT tokens, or OAuth bearer tokens) within a unified storage interface.

### What happens when a user deletes an API key in the UI?

When triggered from the **ModelsConfig** component, a DELETE request to `/api/auth/api-key/[provider]` invokes **AuthStorage** to remove the credential from the `~/.pi/agent` directory. This immediately revokes the application's access to that provider, and subsequent model discovery attempts will fail authentication until a new key is configured.