Authentication
Remi uses Ed25519 keypairs for mutual authentication. Both the server (daemon) and client (web app/phone) prove their identity during every connection.
Overview
Authentication protects against:
- Unauthorized access - only clients with authorized keys can connect
- Man-in-the-middle attacks - mutual authentication ensures you are talking to the real server
- Replay attacks - challenges are one-time use
Server Setup
1. Generate a Server Identity
remi keygen
By default, this creates an unencrypted identity for zero-friction startup. To encrypt with a passphrase:
remi keygen --passphrase
2. Start the Daemon
remi my-project
If your identity is encrypted, you will be prompted for the passphrase at startup. To skip the prompt:
REMI_PASSPHRASE=mypassphrase remi my-project
Unencrypted identities (the default) unlock automatically with no prompt.
Client Setup
Web App
The Remi web app generates a client identity automatically in the Settings panel. You can also:
- Generate a new identity
- Import an existing identity (JSON)
- Export your identity for backup or transfer
Client keys are stored in the browser's localStorage (encrypted).
Sharing Across Devices
To use the same identity on multiple devices:
# On the source device
remi export-key > my-identity.json
# On the target device
remi import-key my-identity.json
To share only the public key (for authorization on the server):
remi export-key --public-only > my-public-key.json
Key Exchange
To authorize a client, the server needs the client's public key:
1. Export the Client's Public Key
On the client device (or from the web app's export):
remi export-key --public-only > client-key.json
2. Transfer to Server
Send client-key.json to the server through any secure channel (SCP, messaging app, USB drive).
3. Authorize on Server
remi authorize client-key.json --label "My Phone"
4. Verify
remi keys
Authorized keys:
a1b2c3d4 My Phone 2026-03-01 last used: never
Connection Handshake
When a client connects, this happens automatically:
- Client sends
hellowith its ID and version - Server sends
auth_challengewith a random one-time challenge and the server's fingerprint and public key - Client signs the challenge with its private key and sends
auth_response - Server verifies the signature against its authorized keys list
- Server signs the same challenge with its own key and sends
auth_result(mutual auth) - Client verifies the server's signature
- Connection is established with
hello_ack
Trust-On-First-Use (TOFU)
The first time a client connects to a server, it stores the server's fingerprint. On subsequent connections, the client checks that the fingerprint has not changed.
If the fingerprint changes (e.g., the server regenerated its identity), the client rejects the connection with a warning. This prevents man-in-the-middle attacks.
To connect to a server with a new identity, clear the old fingerprint from the web app's Settings panel under "Known Hosts."
When Authentication is Required
| Connection Type | Auth Required? |
|---|---|
| Direct WebSocket | Always |
| Relay with rotating code | No (code acts as shared secret) |
| Relay with permanent code | Always |