Floe is designed as developer-first video infrastructure with explicit deployment controls around upload access, file ownership, rate limiting, and operational isolation.
Current security-sensitive surfaces include:
- upload creation and chunk ingestion
- upload finalization and file metadata minting
- file reads and stream access
- metrics and operational endpoints
Floe currently supports:
- request-tier aware rate limiting
- deployment access policies:
public,hybrid, andprivate - pluggable auth providers:
none,local,external, andtoken - env-backed local API key verification for authenticated principals
- optional owner propagation on uploads and file metadata
- optional owner enforcement on upload and file access with
FLOE_ENFORCE_UPLOAD_OWNER=1 - token protection for
/metrics - operational controls through environment-based deployment configuration
Provider contracts:
none- no credential verification
- only valid with
FLOE_ACCESS_POLICY=public
local- verifies
Authorization: Bearer <secret>orx-api-key: <secret>againstFLOE_API_KEYS_JSON
- verifies
external- posts
{ apiKey }or{ delegatedToken }toFLOE_AUTH_EXTERNAL_VERIFY_URL - prefers
x-floe-shared-secret: <FLOE_AUTH_EXTERNAL_SHARED_SECRET>for SaaS verifier auth - still supports
FLOE_AUTH_EXTERNAL_AUTH_TOKENas a backward-compatible fallback - bounded by
FLOE_AUTH_EXTERNAL_TIMEOUT_MS - short positive cache via
FLOE_AUTH_EXTERNAL_CACHE_TTL_MS - verifier auth failures stay transport-level
401 - accepted verifier calls return
200withvalid: true|false, normalized auth fields, and optionalreason; protected routes fail closed when verification fails
- posts
token- verifies HMAC-signed delegated tokens using
FLOE_AUTH_TOKEN_SECRET - rejects malformed, expired, or bad-signature tokens
- verifies HMAC-signed delegated tokens using
Credential precedence:
Authorizationis evaluated beforex-api-key
For production-oriented deployments, Floe should be run in private mode or behind a trusted edge. The core API now supports verified in-service API key authentication, but key management remains environment-backed in this phase.
Recommended deployment posture:
- use
FLOE_ACCESS_POLICY=privatefor restricted deployments - use
FLOE_AUTH_PROVIDER=localfor self-hosted environment-backed keys - use
FLOE_AUTH_PROVIDER=tokenfor delegated signed tokens issued by a control plane - use
FLOE_AUTH_PROVIDER=externalwith a verifier endpoint that normalizes presented bearer tokens or API keys - keep metrics and operational endpoints private
- apply standard network controls, secrets management, and logging hygiene
- use environment-specific credentials and least-privilege access for infrastructure dependencies
Floe supports owner-aware upload and file access flows. When owner enforcement is enabled, access checks are evaluated against the stored owner associated with an upload or file.
Deployments that require restricted content access should ensure uploads are created with a verified owner context.
Recommended hardening areas for production deployments:
- API key storage migration to a hashed persistent store when moving beyond environment-backed key management
- stronger authorization rules for private reads and tenant-scoped access
- principal-aware quotas and abuse controls
- structured security event logging and alerting
Each Floe instance maintains a small local lease (default 20 requests per tenant) before consulting the shared distributed rate limiter. This reduces Redis round-trips for typical request patterns. In single-instance or small-cluster deployments, this is transparent. In larger deployments with precise per-tenant caps, monitor actual request rates against configured limits and adjust FLOE_RATE_LIMIT_FILE_META_LOCAL_LEASE or FLOE_RATE_LIMIT_FILE_STREAM_LOCAL_LEASE if tighter enforcement is required.
Use the admin API (POST /ops/api-keys) or set FLOE_API_KEYS_JSON at startup. The admin API returns a plaintext secret that is shown once — store it in a secrets manager immediately.
Use POST /ops/api-keys/:keyId/rotate to rotate a compromised or aging key. The old key is revoked and a new one is created. All clients using the old key must be updated.
Use DELETE /ops/api-keys/:keyId to permanently revoke a key. This is irreversible. The key is immediately denied all access.
All key lifecycle events (create, revoke, rotate) are logged via emitAuditEvent at warn level with the audit_admin_action event name. Include actor identification from the requesting API key.
If you find a security vulnerability, report it privately to the maintainer before opening a public issue. Include:
- affected endpoint or component
- reproduction steps
- expected vs actual behavior
- impact assessment
- logs or request samples if relevant
API keys can be presented as Authorization: Bearer <secret> or x-api-key: <secret>.
Floe supports two credential formats:
New format (recommended): floe_<keyId>_<secretPart>
keyIdis a short public identifier (e.g.,local-dev,key-1) used for PK lookupsecretPartis the random secret portion hashed with SHA-256 at rest- Example:
floe_local-dev_aB3xY9zW8mNqR5vT2pL7cF4hJ1kD0sG6uE3wX
Legacy format: Any string without the floe_ prefix (e.g., sk_live_abc123)
- The entire string is hashed with SHA-256 and compared via SQL-level hash lookup
parseKeyId()extractskeyIdandsecretPartfrom the presented credential.store.findById(keyId)does a PK lookup (WHERE id = $1 AND revoked_at IS NULL).- The caller computes
SHA-256(secretPart)and usescrypto.timingSafeEqualin-app. - If no key-id is found, a dummy
timingSafeEqualcall normalizes timing.
This avoids the timing side-channel of SQL-level hash comparison.
- The full credential is hashed with SHA-256.
store.findByHash(hash)searches all stored hashes (SQLWHERE secret_hash = $1for Postgres, or iteration withtimingSafeEqualfor env-backed).
Legacy format is silently supported for existing keys. New keys should use the new format.
- Env-backed keys (
FLOE_API_KEYS_JSON): Keys withfloe_prefix use the new fast path. Legacy format keys use iteration withtimingSafeEqual(already constant-time). - Postgres-backed keys (
FLOE_API_KEY_STORE=postgres): Keys withfloe_prefix usefindById(PK lookup, timing-safe). Legacy format keys usefindByHash(SQL hash comparison — the timing side-channel this format was designed to replace).