How it works
The server never sees your data
fetchOnce encrypts your secrets in your browser before anything is sent over the network. The server receives only a blob of ciphertext. It has no decryption key, so it cannot read the contents — not during storage, not during retrieval, not ever. A fully compromised server yields nothing useful.
The encryption key travels only in the URL fragment — the part after the #. Browsers deliberately exclude URL fragments from HTTP requests. The key is never sent to the server.
What encryption is used
Your data is encrypted with AES-256-GCM using the browser's built-in Web Crypto API. The key is 256 bits, generated randomly for each secret. The nonce is 12 random bytes, prepended to the ciphertext before storage. GCM mode provides both confidentiality and integrity — tampering with the stored bytes will cause decryption to fail, not silently produce wrong output.
No external library handles the cryptography. The browser's native implementation is used throughout.
What happens when you create a secret
Your browser collects your key/value pairs and serialises them to JSON. It generates a random 256-bit AES-GCM key and a random 12-byte nonce, then encrypts the JSON. The nonce and ciphertext are concatenated and base64-encoded, then sent to the server via a POST request.
The server stores the ciphertext, a random secret ID, and an expiry time. Nothing else. It does not store your key names, your values, or the encryption key. The link you receive is:
https://fetchonce.com/s/{secret_id}#{encryption_key}
The part after # stays in your browser only. It is never sent to this server.
What happens when the recipient opens the link
The preview page confirms a secret exists for that ID. It shows nothing else — not key names, not values, not a count of entries. When the recipient clicks Reveal, the server performs two operations atomically in a single database transaction: it reads the ciphertext and it deletes the record. The ciphertext is returned to the browser.
The browser extracts the encryption key from the URL fragment, decrypts the ciphertext locally, and displays the key/value pairs. Decrypted data never travels over the network.
If the link is opened a second time, the record no longer exists. The server returns a 404.
Expiry and automatic deletion
Every secret has an expiry time, from 1 hour to 7 days. Secrets that reach their expiry without being revealed are automatically deleted from the database on a regular sweep. An expired secret cannot be retrieved. If you share a link and the recipient does not open it before it expires, the data is gone.
There is no recovery. There is no support escalation that can retrieve a deleted secret. The deletion is permanent.