build · oxidb v0.25.21 0 entries on disk
The /dev/oxide

A build log on shipping OxiDB — notes, post-mortems, and the occasional flame war about JSON parsing, pressed straight onto an embedded engine running inside this process.

posts/0013.md · 2026-04-30

REST + JWT + per-document security rules (Firebase, but smaller)

hero image for: REST + JWT + per-document security rules (Firebase, but smaller)
asset · bucket: blog-images · key: a4145640f48d8960332fc85d.jpg

Set `OXIDB_HTTP_PORT` and OxiDB exposes a REST surface for CRUD, SQL, aggregation, procedures, and blob ops. JSON in, JSON out, CORS, 64-thread pool. The whole Firebase experience without the Google account.

**JWT auth.** `OXIDB_JWT_SECRET` flips on `/auth/signup`, `/auth/login`, `/auth/verify`. HMAC-SHA256 tokens with the `{sub, exp, iat}` claims that everybody expects. Passwords go through Argon2id; the user docs land in the `_auth_users` collection. Verify endpoint returns the claims so a front-end can short-circuit a re-auth round-trip.

**Security rules** live in `_security_rules` and run on every read/write. Each rule is a small expression — `auth.username == doc.owner`, `doc.public == true && request.method == 'read'`. The evaluator is hand-rolled OxiScript, sandboxed (no I/O, no allocations beyond the rule), and per-request cached so the same query against 100 docs evaluates the rule once.

**TTL indexes** with `expireAfterSeconds` let you write Firebase-style ephemeral docs (session tokens, OTPs) directly. SQL surface: `CREATE TTL INDEX ... EXPIRE AFTER N`. Background scanner walks the date-ordered index and deletes from the top.

**WebSocket on the side.** `OXIDB_WS_PORT` exposes the same change-stream the JS SDK consumes. RFC 6455 with no extension negotiation, so any client works.

JS SDK: `npm i oxidb`. Zero deps. Auth + CRUD + SQL + aggregation + onSnapshot, browser AND Node.