Key in the URL or a Separate Passphrase? How One-Time Links Differ
Every end-to-end encrypted one-time secret service has to answer one question: where does the decryption key go? The server must never have it, so it travels to the recipient some other way. There are two common answers, and they protect against different things.
Design 1: the key rides in the link
The sender's browser generates a random key, encrypts the secret, uploads the ciphertext, and builds a link like https://example.com/s/abc123#k3y-m4t3r14l. Everything after the # is the fragment, and browsers never send the fragment to the server. So the server stores ciphertext it cannot read, and the link alone is enough to decrypt it. Privnote, Yopass, PrivateBin, Bitwarden Send, and the original Firefox Send all work this way by default.
What it gets right: one link, one click, and a full-strength 128- or 256-bit random key that no one can guess. The server, its database, and its backups are useless to an attacker.
Where it fails: the link is the secret. Whatever happens to the link happens to the secret:
- It sits in the email thread or chat history you sent it through, and in that service's search, exports, and backups.
- It is synced into browser history on every device the recipient uses.
- It is visible to anyone looking at the screen, and in every screenshot of the conversation.
- It may be fetched by a link-preview bot or an email security scanner — which, depending on the service, either burns the secret or reads it.
The one-time property limits the damage: once the right person has opened it, the leaked link opens nothing. But if someone else gets there first, they read the secret — and the intended recipient finds only a "this secret has already been viewed" page.
Design 2: the link carries no key
Here the key is derived from a passphrase the two people share on a different channel. The link only identifies the ciphertext. OncePad works this way: the sender's browser generates a seven-word passphrase, derives an AES-256 key from it with PBKDF2-HMAC-SHA256 (600,000 iterations), and the link that comes back holds no key at all. The sender pastes the link into email or Slack and reads the passphrase out on a call, or texts it.
What it gets right: the link is harmless on its own. It can sit in a ticket, a chat log, or a forwarded email forever, and it reveals nothing. To read the secret, an attacker needs to compromise two channels at the right moment.
Where it costs:
- It takes a second step: the passphrase has to travel separately, and the recipient has to type it.
- Its strength is the passphrase's strength. A key derived from a human-chosen phrase can be guessed offline by anyone who obtains the ciphertext. This is why OncePad never lets people pick a short phrase: it generates seven random words from a 1,296-word list (about 72 bits), and the slow key derivation makes each guess expensive.
- The ciphertext must stay single-use and short-lived, so an attacker who sees the link cannot quietly collect the ciphertext and guess at leisure. OncePad hands the ciphertext out exactly once and deletes it, and deletes unopened secrets after 24 hours.
The hybrid: a key in the link, plus an optional password
Several key-in-link services add an optional password on top. Done well, this gives you both properties; in practice the password is optional, so most links are sent without one, and the ones that have one usually carry a short, human-chosen password. The design question that matters is what happens by default, because the default is what most secrets get.
Which should you use?
- The link goes somewhere you don't fully control — a ticket system, a shared channel, a client's email, anywhere with search, retention, or an integration reading messages: keep the key out of the link.
- You and the recipient are in a private, ephemeral channel and convenience matters most: a key-in-link service is reasonable.
- The secret is long-lived and valuable — a production database password, a root key: keep the key out of the link, and rotate the credential once it has been set up.
Whichever you pick, check what the service does when a bot opens the link. That is the subject of why link previews burn one-time links.