Skip to content

How resources stay secure

This page explains how Volly resources are secured. If you want the practical, day-to-day side of this instead: see connect real data (resources).

An app’s JavaScript never holds a password, API key, or OAuth token. Volly stores the credential encrypted, and only the server-side gateway decrypts it, at the moment of a proxied request and never before. The app calls a relative URL like /__volly/resources/crm-data/query, and Volly attaches the real credential on the way out.

For Postgres this goes a step further. You never hand Volly an admin password at all: setup generates a SQL script you run yourself, which creates a dedicated read-only role scoped to whichever schemas you chose. Volly only ever stores that role’s connection string.

Database access runs through a role whose own database-level grants allow only SELECT. That’s the real boundary, not something Volly is trusting an app to respect on its own. The gateway adds a second, redundant check on top of that (rejecting anything that isn’t a read-only transaction) purely as defense in depth.

REST APIs work the same way through scoping: connect a key with read-only permissions, and even a compromised app can’t do more than that key allows. Write access (POST, PUT, PATCH, DELETE) only opens up when an admin explicitly grants a specific app read-and-write, and most apps never get it.

One org can never reach another’s resources

Section titled “One org can never reach another’s resources”

Every request is filtered by the organization and app making it, and that’s enforced at the database layer through row-level security, not just checked in application code. An app that hasn’t been granted a resource just gets a plain 404. It can’t tell “doesn’t exist” apart from “exists but you’re not allowed,” so there’s nothing to probe.

Settings → Audit log records who ran what, from which app, against which resource, with the query or request path, the outcome, and how long it took. If a key or connection ever needs investigating, this is the trail; treat the log itself as sensitive, since it can contain the substance of what was queried.

Every resource call must carry the X-Volly-Resource header. That’s not a secret an attacker could steal. It exists because browsers won’t let a cross-site page attach a custom header without a CORS preflight, and Volly’s gateway never answers that preflight. In practice that closes the one gap a SameSite=Lax session cookie leaves open, a cross-site top-level GET navigation, without asking app builders to manage a token themselves.

The gateway can’t be pointed at your internal network

Section titled “The gateway can’t be pointed at your internal network”

The proxy is confined to the exact base URL or database address an admin configured, and it refuses to follow redirects that would send it elsewhere. Requests also leave from Cloudflare’s network, which physically can’t reach private (RFC1918) or link-local addresses, so even a misconfigured resource can’t be turned into a path onto something on your internal network that was never meant to be public.

If a shared encryption key were ever compromised

Section titled “If a shared encryption key were ever compromised”

Credentials sit under a versioned encryption key. If that key ever needed rotating, Volly can add a new one, re-encrypt everything under it, and retire the old key, all without any credential being written out in the clear at any point.