The distinction that matters: transport vs end-to-end

Almost every chat platform uses TLS (Transport Layer Security) to protect your messages while they travel between your browser and the server. This protects against a third party intercepting traffic on the network — your ISP, a coffee shop Wi-Fi owner, a government doing mass surveillance of internet traffic. That protection is real and important.

What TLS doesn't protect against is the platform itself. Once the message arrives at the server over an encrypted connection, TLS has done its job. The server receives the message in plaintext, stores it in a database, and decides what to do with it. For Discord, that means the message is permanently readable by Discord employees, available to law enforcement via subpoena, and present in any breach of Discord's database.

The key distinction: TLS protects your messages from the network. End-to-end encryption protects your messages from the server. Most platforms offer the first. Very few offer the second.

End-to-end encryption means the message is encrypted before leaving your device, using a key the server doesn't hold. The server receives and stores ciphertext. When the recipient opens the message, their device decrypts it using their local key. At no point does the server see readable content.

Recline uses end-to-end encryption. Here's what that means in technical terms, separately for channel messages and direct messages.

Channel message encryption — AES-GCM-256

When you join a Recline server and set up a channel, you provide a passphrase. That passphrase is never sent to the server — it exists only in your browser session. From it, Recline derives an encryption key using PBKDF2-SHA256 (Password-Based Key Derivation Function 2, using SHA-256 as the hash). The key derivation function is intentionally slow, which makes it harder to brute-force the passphrase if an attacker ever obtains the ciphertext.

Here's what happens each time you send a message:

1

Passphrase → key derivation

Your channel passphrase is run through PBKDF2-SHA256 with a channel-specific salt. The output is a 256-bit AES key. This derivation happens in your browser using the Web Crypto API — the passphrase never touches the network.
2

Random IV generation

A fresh 96-bit Initialization Vector (IV) is generated using crypto.getRandomValues() for every single message. Reusing an IV with AES-GCM would be catastrophic — this guarantees it never happens.
3

AES-GCM-256 encryption

The message text is encrypted using AES-GCM-256 with the derived key and the random IV. GCM (Galois/Counter Mode) provides both confidentiality and integrity — the ciphertext includes an authentication tag that detects any tampering.
4

Ciphertext + IV sent to server

Only the ciphertext and IV are transmitted. The server receives these values, stores them in PostgreSQL, and relays them to other channel members. The plaintext message never exists on the server.
5

Decryption on the recipient's device

Recipients who know the channel passphrase derive the same key locally and decrypt the ciphertext in their own browsers. Anyone without the passphrase — including Recline's server — receives bytes they cannot interpret.

AES-GCM-256 is the same cipher used by the U.S. government for classified information, by Signal, by WhatsApp, and by every serious implementation of end-to-end encryption. At 256-bit key size, it has no known practical attack — the key space (2²⁵⁶ possible keys) is larger than estimates of the number of atoms in the observable universe.

Direct message encryption — ECDH P-256

Direct messages require a different approach because there's no shared passphrase — you and the person you're messaging have never been in the same room to agree on one. Recline uses ECDH (Elliptic Curve Diffie-Hellman) key exchange to solve this.

Here's how it works:

1

Each user generates a key pair

When you set up your Recline account, your browser generates an ECDH P-256 keypair — a public key and a private key. Your public key is uploaded to the server. Your private key never leaves your browser and is cleared when you log out.
2

Public key exchange via server

When you start a DM conversation, your browser fetches the recipient's public key from the server. They fetch yours. The server acts as a directory — it stores and delivers public keys, but cannot derive the shared secret from them alone.
3

Shared secret via ECDH

Each party independently computes the same shared secret using their own private key and the other person's public key. This is the mathematical property of Diffie-Hellman: Alice's private key + Bob's public key yields the same value as Bob's private key + Alice's public key. The server, which only has both public keys, cannot compute this secret.
4

Key derivation via HKDF-SHA256

The raw ECDH shared secret is run through HKDF-SHA256 (HMAC-based Key Derivation Function) to produce a well-formatted AES-256 key. This step ensures the key has appropriate entropy distribution regardless of the raw ECDH output.
5

AES-GCM-256 encryption, as above

DMs are then encrypted with AES-GCM-256 using the derived key, with a fresh random IV per message. The server stores and relays ciphertext. It is a blind relay for DM content — no keys, no plaintext, no visibility into what was said.

ECDH P-256 is the elliptic curve variant of Diffie-Hellman key exchange, using the NIST P-256 curve (also known as secp256r1). It's the same key exchange mechanism used by Signal, iMessage, and most modern TLS connections. The mathematical hardness assumption underlying it — the elliptic curve discrete logarithm problem — has been studied extensively and has no known efficient attack.

What the server stores

To be specific about what exists in Recline's PostgreSQL database:

WHAT'S IN THE DATABASE
messages AES-GCM ciphertext + IVThe encrypted bytes and initialization vector. Without the channel passphrase, this is unreadable data.
dm_messages AES-GCM ciphertext + IV + sender public keySame encrypted format. The sender's public key is stored for historical DM decryption after key rotation.
users Username + Argon2id hash + ECDH public keyThe Argon2id hash of your password (not the password). Your public key (not the private key). No email, phone, or personal information.
sessions 256-bit random hex tokenSession authentication token. No JWT, no claims, no embedded user data.
servers Server name + KDF saltThe salt used for key derivation. Changing the passphrase re-rolls the salt and rotates to a new key.

A complete database dump of Recline contains no readable message content. Law enforcement with a valid court order receives usernames, timestamps, channel membership records, and ciphertext. The ciphertext is useless without the channel passphrase, which the server doesn't hold. For DMs, the shared secret is derived from private keys that live only in users' browsers and are cleared on logout.

Why open source matters for verifying this

Every claim in this article is verifiable. The encryption logic lives in the open-source client on GitHub, primarily in client/src/lib/crypto.ts. The key functions are:

  • deriveKey(passphrase, salt) — PBKDF2-SHA256 key derivation
  • encryptMessage(key, plaintext) — AES-GCM-256 encryption with random IV
  • decryptMessage(key, ciphertext, iv) — AES-GCM-256 decryption
  • generateDmKeyPair() — ECDH P-256 keypair generation
  • deriveDmSharedKey(myPrivateKey, theirPublicKey) — ECDH + HKDF-SHA256

All of these use the Web Crypto API — the browser's built-in cryptographic primitives, implemented by the browser vendor, not Recline. Recline's code coordinates the encryption operations; the actual cryptographic work is done by code you're already trusting when you use HTTPS.

The open-source guarantee: if any of the encryption described here were missing or broken, it would be visible in the source code. No audit required. The code is the audit.

What this means in practice

The practical implications of this architecture aren't abstract. A breach of Recline's server returns encrypted data with no keys to decrypt it. A subpoena returns metadata — who talked to whom, when, in which channel — but not message content. An insider at Recline cannot read your conversations. A malicious modification of the server cannot expose plaintext, because plaintext never arrives there.

This is different from a company's security posture or a promise made in a privacy policy. Both of those can change. The architecture can't — not without breaking the client's decryption logic, which is public and would be immediately visible to anyone reading the code.

For groups where private communication actually matters — not in the abstract, but in practice — the specific mechanism of the encryption is worth understanding. "We take privacy seriously" is a sentence. AES-GCM-256 with PBKDF2-SHA256 key derivation and ECDH P-256 for DMs is a technical constraint. They are not the same thing.