Access

Introduction

Caller authorization always runs before a concurrency slot is taken. Configure caller auth on the source's Access tab. Upstream secrets for managed sources live under Credentials.

Checks run in this order: IP policies → JWT / Cloudflare Access → access key.

Access keys

An access key admits callers to one source. There are two kinds, and both go in the same header:

  • Keys you create under Sources → Access → Create key, or with the Control API. Today they start with nb_live_.
  • Session tokens that agents get from start_source_session over MCP. They start with sv_at_ and always expire. See Session tokens.

Send the key with X-Swarmvia-Key:

curl -sS "https://your-source.swarmvia.cloud/v1/records" \
  -H "X-Swarmvia-Key: $ACCESS_KEY"

On managed sources you may instead send Authorization: Bearer $ACCESS_KEY or Authorization: Swarmvia $ACCESS_KEY. Authorization: Nthbouncer is still accepted. X-Nthpool-Key is still accepted.

On pass-through sources, always use X-Swarmvia-Key for the access key so Authorization can carry the upstream credential.

Missing or invalid keys return 401. The message says why; see Understand admission errors.

Session tokens

When an agent calls start_source_session, swarmvia signs a short-lived access token for that source and returns it with its expires_at. The token works only on the source it was issued for, with the access it was issued with (read or write), and acts for the member who connected the agent.

  • Lifetime: 1 hour by default. The agent may ask for 24h or 7d with expires_in. A session token cannot be made non-expiring.
  • Revocation: a token expires on its own, so nothing needs to end a session when the work is done. Revoke a token only if it leaked: on the Access tab, or with revoke_source_session from the agent. It stops working at once.
  • Expiry: an expired token returns 401 with access token expired. The agent starts a new session and carries on. Tokens are not renewed in place.

A new token works on its first request: swarmvia checks its signature, so there is nothing to wait for.

Keys you create are moving to short-lived tokens too. Until then they work as they always have.

Keys that act for a member

A key minted with Acts for: Me carries your identity. The source's logs name you as the caller, and a per-member credential uses your own connected account for its calls. Keys agents mint over MCP act for the member who connected the agent. Leave Acts for off for machine keys such as CI.

When a member is removed from the org or leaves it, the keys that act for them are revoked. Machine keys are not affected.

Write blocking

Each key either blocks writes (default) or has writes allowed. With writes blocked, the key admits GET, HEAD, and OPTIONS only. Every other method returns 403 before the request reaches your origin, and before it takes a concurrency slot.

On Access, under the access keys, you can add methods this origin uses for reads. SuiteQL and GraphQL are POST. Paths belong to that method only. Leave a method's paths blank to allow it everywhere, or list prefixes (/services/rest/query/) so other POSTs stay blocked.

Leave writes blocked for callers that only fetch: retrieval agents, dashboards, search indexers. It means a prompt injection or a buggy loop cannot delete a record no matter what it sends.

Keys minted before this option existed have writes allowed and are unchanged.

The lock API is not affected: acquiring, renewing, and releasing a concurrency slot are coordination calls, not writes to your origin, so a writes-blocked key can still do them.

On a database source the HTTP method is not the write gate. Every query is a POST, including a read. The write boundary is the Postgres role swarmvia connects as. In v1 that is always the read role, so a writes-allowed key and a writes-blocked key connect the same way. A statement that tries to write is refused by the database (403, SQLSTATE 25006), not by the key's method list. MCP query tools (source_query, source_schema, source_count_rows) are read-only; there is no write tool to hide.

Origin verification (outbound HMAC)

Enable Origin verification on Sources → Access. swarmvia then signs every request it forwards so your origin can prove traffic came through swarmvia and reject direct callers.

The canonical string hashes only the first 1 MB of the body and binds Content-Length, so large uploads can stream. The secret is a source-level osk_… value (shown once when you enable or rotate).

What swarmvia sends upstream

After stripping every inbound X-Swarmvia-* header (callers cannot forge these), swarmvia adds:

Header Value
X-Swarmvia-Timestamp Fresh epoch seconds
X-Swarmvia-Nonce Fresh UUID (new on every attempt, including retries)
X-Swarmvia-Signature Hex HMAC-SHA256 of the outbound canonical string with osk_…

Canonical string (fields joined with \n):

METHOD
PATH
QUERY
SHA256(BODY_PREFIX)
CONTENT_LENGTH
TIMESTAMP
NONCE

PATH / QUERY are what the origin receives (forwarded verbatim). BODY_PREFIX is the first min(body length, 1 MiB) raw bytes (empty body → SHA-256 of empty input). CONTENT_LENGTH is the decimal full body length swarmvia forwards (0 when empty).

Limits

Limit Behavior
Prefix window 1 MB Only the first mebibyte is hashed; the rest streams
Declared Content-Length on large bodies Preferred; bodies over 1 MB stream without a 10 MB reject
No Content-Length and body > 10 MB 413 payload_too_large (length cannot be bound without buffering)
Clock skew at origin Match ±300 seconds

Nonce replay defense at the origin is optional (swarmvia already mints a fresh nonce per attempt). Retry-on-429 still needs a re-readable body under 10 MB; larger bodies with a declared length run as a single streamed attempt and are still prefix-signed.

Rotation

Mint a new secret, update the origin to accept both old and new, then Activate in the dashboard. Discard a pending secret if you abort the rotation.

Worked verification code: Determine a request came from the proxy.

Caller JWT (plan-gated)

Configure a JWKS URL (and optional issuer / audience) on Access. Prefer the X-Swarmvia-Jwt header. On pass-through sources, a bearer JWT may also be accepted in Authorization when that does not conflict with upstream auth needs.

Cloudflare Access (plan-gated)

Configure team domain and application audience on Access. Send the Access JWT as Cf-Access-Jwt-Assertion or X-Swarmvia-Jwt.

Worked setup: Configure Cloudflare Zero Trust.

IP policies (plan-gated)

Attach an IP policy to the source. Requests from a blocked range, or from outside the allowed ranges when an allow policy is attached, receive 403 before other auth checks. Policy edits take effect within a few seconds.

Next steps