# Security Best Practices for God's Eye View: Protecting API Keys and Hardening Your Instance

> Learn essential security best practices for God's Eye View. Protect API keys, harden your instance with server-side secrets, restricted tokens, and robust proxy security.

- Repository: [Bilawal Sidhu/gods-eye-view](https://github.com/bilawalsidhu/gods-eye-view)
- Tags: best-practices
- Published: 2026-09-05

---

**The God's Eye View security model keeps all secret-bearing API keys server-side, exposes only intentionally client-side tokens with strict restrictions, and hardens the Vite dev proxy with request validation, size caps, and per-IP rate limiting.**

God's Eye View (GEV) is a **local-first web client** that visualizes multiple public-data layers through third-party APIs. Because the application communicates with numerous external services—OpenAI, Google Maps, Cesium Ion, and OpenStreetMap data feeds—its **security best practices** focus on **credential isolation**, **proxy hardening**, and **controlled network exposure**. This guide walks through the safeguards implemented in the `bilawalsidhu/gods-eye-view` repository and how to apply them in your deployment.

---

## Core Security Principle: Secrets Stay Server-Side

The foundational rule is documented in [[`SECURITY.md`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/SECURITY.md)](https://github.com/bilawalsidhu/gods-eye-view/blob/main/SECURITY.md#L14-L31):

> **"The golden rule: secret-bearing API keys stay on the server side."**

The GEV architecture enforces this through **token tiering**:

| Token Type | Examples | Exposure | Lifetime |
|------------|----------|----------|----------|
| **Server-side secrets** | `OPENAI_API_KEY`, `PINOKIO_ENV_FILE` | Never reaches browser | Persistent (stored in `.env` or Keychain) |
| **Short-lived session tokens** | OpenAI Realtime ephemeral tokens | Returned via authenticated `/api/realtime/token` | Minutes |
| **Public client tokens** | `GOOGLE_MAPS_API_KEY`, `CESIUM_ION_TOKEN` | Visible in `import.meta.env` | Long-lived, but restricted by provider |

Only **two keys are deliberately client-side**—Google Maps and Cesium Ion—and both must be **restricted in their provider consoles** through referrer allowlists and read-only asset scopes.

---

## Secure Key Management with the POWER UP Panel

GEV provides a built-in UI for adding provider credentials without manual file editing. The **POWER UP** panel (implemented in [`src/keySetupCore.mjs`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/src/keySetupCore.mjs)) handles key persistence securely:

1. User enters keys through the web interface
2. Values are written to `.env` (git-ignored) or macOS Keychain
3. The development server auto-restarts to load new credentials

```javascript
// Example: Adding keys via the POWER UP flow
// In the running app, click the "POWER UP" chip → Provider Settings
// Paste your Cesium Ion token (public read-only) and save.
// The panel writes to .env and triggers a Vite restart.

```

**Critical:** Never commit `.env` files. The repository includes [`.env.example`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/.env.example) as a template without real values.

---

## Hardening the Development Proxy

All external API traffic routes through Vite's dev server, defined in [[`vite.config.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/vite.config.js)](https://github.com/bilawalsidhu/gods-eye-view/blob/main/vite.config.js). The proxy implements multiple defense layers:

### Request Validation and Size Limits

```javascript
// vite.config.js – Overpass API protection (excerpt)
// Lines 15-30: Validates URLs, caps request/response sizes
const OVERPASS_MAX_BODY_BYTES = 1024 * 1024;      // 1 MB
const OVERPASS_MAX_RESPONSE_BYTES = 10 * 1024 * 1024; // 10 MB

```

The proxy **rejects arbitrary URLs** and enforces per-endpoint size limits to prevent abuse and memory exhaustion.

### Secret-Only Proxy Logic

```javascript
// vite.config.js – Lines 44-55
// Client keys are explicitly whitelisted; secrets remain server-bound
function clientKey(envName) {
  return (name) => name === envName ? process.env[envName] : undefined;
}

```

This ensures that even if the client attempts to access `OPENAI_API_KEY`, the proxy returns `undefined`—the key never enters the browser bundle.

### Per-IP Rate Limiting for Cost-Bearing Endpoints

Lines 84-101 of [[`vite.config.js`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/vite.config.js)](https://github.com/bilawalsidhu/gods-eye-view/blob/main/vite.config.js#L84-L101) implement **opt-in throttling** for paid APIs:

```bash

# Enable per-IP rate limiting in .env

echo "GEV_RATELIMIT_OPENAI_PER_MIN=30" >> .env
echo "GEV_RATELIMIT_GOOGLE_PER_MIN=60" >> .env

```

When limits are exceeded, the proxy returns **HTTP 429** without forwarding the request to the provider, protecting quota and budget.

---

## Restricting Client-Side API Keys

Since Google Maps and Cesium Ion tokens are visible in browser DevTools, **provider-side restrictions are mandatory**:

### Google Maps API Key

```bash

# Google Cloud Console → Credentials → API Key

# Application restrictions: HTTP referrers (e.g., https://localhost:4173/*)

# API restrictions: Maps JavaScript API, Places API, Tile API

echo "GOOGLE_MAPS_API_KEY=AIzaSy...restricted" >> .env

```

### Cesium Ion Token

- Create a **public token** with `assets:read` scope only
- Apply **URL restrictions** in the Cesium dashboard
- Never use your default (private) token for client applications

---

## Network Exposure: Localhost by Default

By design, GEV binds to **localhost** (`127.0.0.1`). If you intentionally expose the server on a LAN:

```bash
HOST=0.0.0.0 npm run dev

```

**Critical warning from [`README.md#L54-L63`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/README.md#L54-L63):** Every device on your network can consume your API quotas. Always pair LAN exposure with:

- **Per-IP rate limits** (`GEV_RATELIMIT_*` variables)
- **Firewall rules** at the OS level
- **Regular quota monitoring** in provider consoles

---

## Redacted Logging and Audit Trails

Debug logs are persisted to `.gev-logs/` with **automatic redaction** of sensitive data:

| Redacted Field | Reason |
|----------------|--------|
| API keys | Prevent credential leakage in log files |
| Bearer tokens | Short-lived but still sensitive |
| Image data | Privacy and size reduction |

See [`SECURITY.md#L52-L53`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/SECURITY.md#L52-L53) for the redaction policy.

---

## Data Provenance and Compliance

All visualization layers source from **public, documented APIs** with proper attribution. The [[`DATA_SOURCES.md`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/DATA_SOURCES.md)](https://github.com/bilawalsidhu/gods-eye-view/blob/main/DATA_SOURCES.md) file maps each layer to its official documentation and terms of service. Respect these policies when scaling usage—GEV's internal throttles are **not** billing caps.

---

## Verification: Confirming Secrets Stay Hidden

You can verify the client-side exposure model by inspecting `import.meta.env` in your browser console:

```javascript
// In src/main.js or browser DevTools:
import.meta.env.GOOGLE_MAPS_API_KEY   // ✓ Defined (public, restricted)
import.meta.env.CESIUM_ION_TOKEN      // ✓ Defined (public, restricted)
import.meta.env.OPENAI_API_KEY         // ✗ Undefined (never exposed)

// OpenAI features work via ephemeral token from /api/realtime/token

```

If `OPENAI_API_KEY` appears anywhere in the client bundle, your configuration is compromised.

---

## Summary

- **Keep secrets server-side**—use `.env` or Keychain, never commit credentials
- **Restrict the two client-side keys** (Google Maps, Cesium Ion) in provider consoles
- **Run behind the built-in proxy**—it validates URLs, caps sizes, sanitizes errors, and rate-limits
- **Use POWER UP panel** for secure key entry with automatic server restart
- **Limit network exposure**—localhost default; LAN requires explicit rate limiting
- **Monitor quotas externally**—GEV throttles protect against abuse, not billing

---

## Frequently Asked Questions

### How does God's Eye View protect my OpenAI API key?

Your `OPENAI_API_KEY` **never reaches the browser**. The server holds it in environment variables and exchanges it for **short-lived, scoped session tokens** via the `/api/realtime/token` endpoint. Clients receive only ephemeral tokens valid for minutes, not your permanent credential. This is enforced by the proxy logic in [`vite.config.js#L44-L55`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/vite.config.js#L44-L55).

### Can I safely share my God's Eye View instance with my team?

Only with precautions. Binding to `0.0.0.0` exposes your API quotas to all LAN devices. Before sharing, set **per-IP rate limits** (`GEV_RATELIMIT_OPENAI_PER_MIN`, `GEV_RATELIMIT_GOOGLE_PER_MIN`), monitor usage in provider dashboards, and consider running behind a reverse proxy with additional authentication. See [[`README.md`](https://github.com/bilawalsidhu/gods-eye-view/blob/main/README.md)](https://github.com/bilawalsidhu/gods-eye-view/blob/main/README.md#L54-L63) for the official guidance.

### Why are Google Maps and Cesium Ion tokens visible in the client?

These services **require browser-side initialization**—Google Maps JavaScript loads directly from Google's servers, and Cesium renders 3D tiles in WebGL. The security model shifts to **provider-side restrictions**: referrer allowlists, URL restrictions, and minimal scopes (`assets:read` for Cesium). Treat these as **capable but bounded** credentials, not secrets.

### What happens if I exceed the per-IP rate limit?

The Vite proxy returns **HTTP 429 Too Many Requests** immediately, without forwarding to the upstream API. This protects your quota but may interrupt functionality for that IP. Adjust limits in `.env` based on your expected usage pattern, or disable throttling entirely (not recommended for shared instances).