docs: rewrite mdBook documentation for v2 architecture

Update 25+ files and add 6 new pages to reflect the v2 migration from
Cap'n Proto to Protobuf framing over QUIC. Integrates SDK and Operations
docs into the mdBook, restructures SUMMARY.md, and rewrites the wire
format, architecture, and protocol sections with accurate v2 content.
This commit is contained in:
2026-03-04 22:02:31 +01:00
parent f7a7f672b4
commit d073f614b3
31 changed files with 4423 additions and 2379 deletions

View File

@@ -1,149 +1,215 @@
# Auth Schema
**Schema file:** `schemas/auth.capnp`
**File ID:** `@0xb3a8f1c2e4d97650`
**Proto file:** `proto/qpq/v1/auth.proto`
**Package:** `qpq.v1`
**Method IDs:** 100-103
The `AuthenticationService` interface defines the RPC contract for uploading and fetching MLS KeyPackages. It is the standalone version of the Authentication Service; in the current architecture, these methods are integrated into the unified [NodeService](node-service-schema.md) interface.
The auth proto defines the OPAQUE asymmetric password-authenticated key exchange (PAKE) messages used for user registration and login. OPAQUE never transmits the password to the server; the server learns only a random value derived from the password.
Registration is a two-round-trip flow (start + finish). Login is a two-round-trip flow (start + finish). On successful login, the server returns a `session_token` used to authenticate subsequent RPCs.
See [Authentication Service Internals](../internals/authentication-service.md) for the server-side implementation and the full flow diagram.
---
## Full schema listing
## Full proto listing
```capnp
# auth.capnp -- Authentication Service RPC interface.
#
# Clients call uploadKeyPackage before joining any group so that peers can
# fetch their key material to add them. Each KeyPackage is single-use (MLS
# requirement): fetchKeyPackage removes and returns one package atomically.
#
# The server indexes packages by the raw Ed25519 public key bytes (32 bytes),
# not a fingerprint, so callers must know the target's identity public key
# out-of-band (e.g. from a directory or QR code scan).
#
# ID generated with: capnp id
@0xb3a8f1c2e4d97650;
```protobuf
syntax = "proto3";
package qpq.v1;
interface AuthenticationService {
# Upload a single-use KeyPackage for later retrieval by peers.
#
# identityKey : Ed25519 public key bytes (exactly 32 bytes).
# package : openmls-serialised KeyPackage blob (TLS encoding).
#
# Returns the SHA-256 fingerprint of `package`. Clients should record this
# and compare it against the fingerprint returned by a peer's fetchKeyPackage
# to detect tampering.
uploadKeyPackage @0 (identityKey :Data, package :Data) -> (fingerprint :Data);
// OPAQUE registration + login (4 methods).
// Method IDs: 100-103.
# Fetch and atomically remove one KeyPackage for a given identity key.
#
# Returns empty Data if no KeyPackage is currently stored for this identity.
# Callers should handle the empty case by asking the target to upload more
# packages before retrying.
fetchKeyPackage @1 (identityKey :Data) -> (package :Data);
message OpaqueRegisterStartRequest {
string username = 1;
bytes request = 2;
}
message OpaqueRegisterStartResponse {
bytes response = 1;
}
message OpaqueRegisterFinishRequest {
string username = 1;
bytes upload = 2;
bytes identity_key = 3;
}
message OpaqueRegisterFinishResponse {
bool success = 1;
}
message OpaqueLoginStartRequest {
string username = 1;
bytes request = 2;
}
message OpaqueLoginStartResponse {
bytes response = 1;
}
message OpaqueLoginFinishRequest {
string username = 1;
bytes finalization = 2;
bytes identity_key = 3;
}
message OpaqueLoginFinishResponse {
bytes session_token = 1;
}
```
---
## Method-by-method analysis
## Registration flow (IDs 100-101)
### `uploadKeyPackage @0`
User registration takes two round trips. The `request` and `response` fields carry opaque OPAQUE protocol blobs; their internal structure is defined by the `opaque-ke` crate.
### OpaqueRegisterStart (ID 100)
```
uploadKeyPackage (identityKey :Data, package :Data) -> (fingerprint :Data)
Client Server
| |
| OpaqueRegisterStartRequest |
| username: "alice" |
| request: <OPAQUE blob> |
| -----------------------------> |
| |
| OpaqueRegisterStartResponse |
| response: <OPAQUE blob> |
| <----------------------------- |
```
**Purpose:** A client uploads a single-use MLS KeyPackage so that peers can later fetch it to add the client to a group.
**Request fields:**
**Parameters:**
| Field | Type | Description |
|-------|------|-------------|
| `username` | `string` | The username being registered. Must be unique on the server. |
| `request` | `bytes` | OPAQUE `RegistrationRequest` blob generated by the client using the `opaque-ke` crate. |
| Parameter | Type | Size | Description |
|---|---|---|---|
| `identityKey` | `Data` | Exactly 32 bytes | The uploader's raw Ed25519 public key bytes. This is the index key under which the package is stored. |
| `package` | `Data` | Variable (bounded by transport max) | An openmls-serialised KeyPackage blob in TLS encoding. Contains the client's HPKE init key, credential, and signature. |
**Response fields:**
**Return value:**
| Field | Type | Description |
|-------|------|-------------|
| `response` | `bytes` | OPAQUE `RegistrationResponse` blob generated by the server. Client feeds this into the finish step. |
| Field | Type | Size | Description |
|---|---|---|---|
| `fingerprint` | `Data` | 32 bytes | SHA-256 digest of the uploaded `package` bytes. |
**Fingerprint semantics:** The returned fingerprint allows the uploading client to verify that the server stored the package correctly. More importantly, when a peer later fetches a KeyPackage, it can compare the fetched package's SHA-256 hash against the fingerprint (communicated out-of-band) to detect tampering by a malicious server.
**Idempotency:** Uploading the same package twice appends a second copy to the queue. The server does not deduplicate. Clients should avoid uploading duplicates to conserve their KeyPackage supply.
### `fetchKeyPackage @1`
### OpaqueRegisterFinish (ID 101)
```
fetchKeyPackage (identityKey :Data) -> (package :Data)
Client Server
| |
| OpaqueRegisterFinishRequest |
| username: "alice" |
| upload: <OPAQUE record> |
| identity_key: <32 bytes> |
| -----------------------------> |
| |
| OpaqueRegisterFinishResponse |
| success: true |
| <----------------------------- |
```
**Purpose:** Fetch and atomically remove one KeyPackage for a given identity. This is the mechanism by which a group creator obtains a peer's key material in order to add them to a group via MLS `add_members()`.
**Request fields:**
**Parameters:**
| Field | Type | Description |
|-------|------|-------------|
| `username` | `string` | Must match the username from the start request. |
| `upload` | `bytes` | OPAQUE `RegistrationUpload` blob. The server stores this as the user's OPAQUE record; it contains the password-derived key material without revealing the password. |
| `identity_key` | `bytes` | The user's Ed25519 identity public key (32 bytes). Stored alongside the OPAQUE record and used as the user's long-term identifier for key packages and delivery queues. |
| Parameter | Type | Size | Description |
|---|---|---|---|
| `identityKey` | `Data` | Exactly 32 bytes | The raw Ed25519 public key of the target peer whose KeyPackage is being requested. |
**Response fields:**
**Return value:**
| Field | Type | Size | Description |
|---|---|---|---|
| `package` | `Data` | Variable, or 0 bytes | The fetched KeyPackage blob, or empty `Data` if no packages are stored for this identity. |
**Atomic removal:** The fetch operation is destructive: it removes the returned KeyPackage from the server's store in the same operation that returns it. This guarantees MLS's single-use requirement -- a KeyPackage is never served to two different requesters.
**Empty response handling:** Callers must check for an empty response. An empty `package` means the target has no KeyPackages available. The caller should either:
1. Retry after a delay, hoping the target uploads more packages.
2. Signal the user that the target is unreachable for group addition.
| Field | Type | Description |
|-------|------|-------------|
| `success` | `bool` | `true` if the registration record was stored successfully. `false` if the username is already taken or another error occurred. |
---
## Indexing by raw Ed25519 public key
## Login flow (IDs 102-103)
The Authentication Service indexes KeyPackages by the **raw 32-byte Ed25519 public key**, not by a fingerprint or any higher-level identifier. This design choice has several implications:
User login also takes two round trips. On success, the server issues a `session_token` that the client attaches to subsequent authenticated RPCs.
1. **No directory service required for lookup.** The caller must already know the target's Ed25519 public key (obtained out-of-band via QR code scan, manual exchange, or a future directory service).
### OpaqueLoginStart (ID 102)
2. **Consistent with DS indexing.** The [Delivery Service](delivery-schema.md) uses the same 32-byte Ed25519 key as its queue index, so a single key serves as the universal identifier across both services.
```
Client Server
| |
| OpaqueLoginStartRequest |
| username: "alice" |
| request: <OPAQUE blob> |
| -----------------------------> |
| |
| OpaqueLoginStartResponse |
| response: <OPAQUE blob> |
| <----------------------------- |
```
3. **No ambiguity.** Unlike fingerprints (which could collide if truncated) or human-readable names (which require a mapping layer), the raw public key is the canonical, collision-resistant identifier.
**Request fields:**
| Field | Type | Description |
|-------|------|-------------|
| `username` | `string` | The username logging in. |
| `request` | `bytes` | OPAQUE `CredentialRequest` blob generated by the client. |
**Response fields:**
| Field | Type | Description |
|-------|------|-------------|
| `response` | `bytes` | OPAQUE `CredentialResponse` blob. Contains the server's masked public key and envelope for the client to derive its export key. |
### OpaqueLoginFinish (ID 103)
```
Client Server
| |
| OpaqueLoginFinishRequest |
| username: "alice" |
| finalization: <OPAQUE blob> |
| identity_key: <32 bytes> |
| -----------------------------> |
| |
| OpaqueLoginFinishResponse |
| session_token: <32 bytes> |
| <----------------------------- |
```
**Request fields:**
| Field | Type | Description |
|-------|------|-------------|
| `username` | `string` | Must match the username from the start request. |
| `finalization` | `bytes` | OPAQUE `CredentialFinalization` blob containing the client's proof of knowledge of the password. The server verifies this against its stored OPAQUE record. |
| `identity_key` | `bytes` | The user's Ed25519 identity public key (32 bytes). The server verifies this matches the key registered during `OpaqueRegisterFinish`. |
**Response fields:**
| Field | Type | Description |
|-------|------|-------------|
| `session_token` | `bytes` | Opaque bearer token (32 bytes). Included in subsequent RPC requests to authenticate the session. The server associates this token with the user's identity and device. |
If login fails (wrong password, unknown username, or identity key mismatch), the server returns an error status in the response frame; the `session_token` field is empty.
---
## Single-use semantics
## Session token usage
MLS requires that each KeyPackage be used at most once to preserve the forward secrecy of the initial key exchange. The Authentication Service enforces this by atomically removing the KeyPackage on fetch.
After a successful `OpaqueLoginFinish`, the client uses the `session_token` as a bearer credential for all authenticated RPC methods. The token is passed at the QUIC connection level (not per-frame); the server validates it on connection establishment and maintains the association for the lifetime of the connection.
**Consequences for clients:**
The `Auth` message in `common.proto` carries the token for federation and internal use:
- Clients should **pre-upload multiple KeyPackages** after generating their identity, so that several peers can add them to groups concurrently without exhausting the supply.
- Clients should **monitor their KeyPackage count** on the server (via a future monitoring endpoint or periodic re-upload) and replenish when the supply runs low.
- If a client has zero KeyPackages stored, it is effectively unreachable for new group invitations until it uploads more.
For the design rationale behind single-use KeyPackages, see [ADR-005: Single-Use KeyPackages](../design-rationale/adr-005-single-use-keypackages.md).
---
## Relationship to NodeService
In the current unified architecture, the Authentication Service methods are exposed as part of the [NodeService interface](node-service-schema.md):
| AuthenticationService Method | NodeService Method | Additional Parameters |
|---|---|---|
| `uploadKeyPackage @0` | `uploadKeyPackage @0` | `auth :Auth` |
| `fetchKeyPackage @1` | `fetchKeyPackage @1` | `auth :Auth` |
The standalone `AuthenticationService` interface remains in the schema for documentation purposes and for use in contexts where the full NodeService is not needed.
```protobuf
message Auth {
bytes access_token = 1;
bytes device_id = 2;
}
```
---
## Further reading
- [Wire Format Overview](overview.md) -- serialisation pipeline context
- [NodeService Schema](node-service-schema.md) -- unified interface that subsumes AuthenticationService
- [Delivery Schema](delivery-schema.md) -- the companion service for message routing
- [Envelope Schema](envelope-schema.md) -- legacy framing that used `keyPackageUpload`/`keyPackageFetch` message types
- [ADR-005: Single-Use KeyPackages](../design-rationale/adr-005-single-use-keypackages.md) -- design rationale for atomic removal on fetch
- [ADR-004: MLS-Unaware Delivery Service](../design-rationale/adr-004-mls-unaware-ds.md) -- why the server does not inspect MLS content
- [Wire Format Overview](overview.md) -- frame format and transport parameters
- [Method ID Reference](envelope-schema.md) -- all 44 method IDs
- [Authentication Service Internals](../internals/authentication-service.md) -- server-side OPAQUE flow and session management
- [RPC Reference](node-service-schema.md) -- all proto definitions