@opensurf/inbox

A minimal, zero-dependency, open-source OTP inbox for OpenSurf.

It receives forwarded email, extracts a numeric one-time password, stores it for ~60 seconds, and exposes a read-once HTTP API.


About OpenSurf

OpenSurf builds infrastructure for reliable, user-controlled web agents. We believe that capbility, reliability and privacy are essential attributes of automated systems.

Find out more at https://opensurf.ai


Official service

If you just want to use it, the hosted service lives at https://opensurf.io/inbox/create

The source for that service live here https://github.com/opensurfai/inbox


Why this is secure (short answer)

This system is intentionally small and treats OTPs as short-lived, opaque secrets. Security relies on three guarantees:

  1. Unforgeable routing
    Inbox addresses embed an HMAC signature. Without EMAIL_INBOX_SECRET, attackers cannot guess or mint valid inbox keys.

  2. Unforgeable reads
    Reads require a separate HMAC-derived API key. Knowing the inbox address does not grant read access.

  3. Short retention + read-once
    OTPs expire quickly (~60s) and are deleted after the first successful read.

This keeps the blast radius small: no long-term storage, no mailbox history, and no recovery path for missed or leaked codes.


Self-hosting

The inbox is designed to run on Cloudflare Workers + Durable Objects via alchemy.

Requirements

Configure

Create .env in lib/inbox:

ALCHEMY_PASSWORD='...'
EMAIL_INBOX_SECRET='...'
EMAIL_INBOX_DOMAIN='your-domain.example'

EMAIL_INBOX_SECRET should be a strong, private secret (distinct from ALCHEMY_PASSWORD).

Run locally

bun run dev

Deploy

bun run deploy

After deployment, your API will be available at your domain, and emails routed to <inboxKey>@your-domain.example.


API quickstart

  1. Create inbox:
GET /inbox/create
  1. Fetch OTP:
GET /inbox/<inboxKey>/otp?sender=example.com
Authorization: Bearer <apiKey>

Responses are JSON strings (the code) or null if none are available.