Security Best Practices for God's Eye View: Protecting API Keys and Hardening Your Instance
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#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) handles key persistence securely:
- User enters keys through the web interface
- Values are written to
.env(git-ignored) or macOS Keychain - The development server auto-restarts to load new credentials
// 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 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). The proxy implements multiple defense layers:
Request Validation and Size Limits
// 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
// 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#L84-L101) implement opt-in throttling for paid APIs:
# 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
# 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:readscope 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:
HOST=0.0.0.0 npm run dev
Critical warning from 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 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) 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:
// 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
.envor 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.
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#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).
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →