Files
quicproquo/docs/src/wire-format/auth-schema.md
Christian Nennemann 2e081ead8e chore: rename quicproquo → quicprochat in docs, Docker, CI, and packaging
Rename all project references from quicproquo/qpq to quicprochat/qpc
across documentation, Docker configuration, CI workflows, packaging
scripts, operational configs, and build tooling.

- Docker: crate paths, binary names, user/group, data dirs, env vars
- CI: workflow crate references, binary names, artifact names
- Docs: all markdown files under docs/, SDK READMEs, book.toml
- Packaging: OpenWrt Makefile, init script, UCI config (file renames)
- Scripts: justfile, dev-shell, screenshot, cross-compile, ai_team
- Operations: Prometheus config, alert rules, Grafana dashboard
- Config: .env.example (QPQ_* → QPC_*), CODEOWNERS paths
- Top-level: README, CONTRIBUTING, ROADMAP, CLAUDE.md
2026-03-21 19:14:06 +01:00

7.0 KiB

Auth Schema

Proto file: proto/qpc/v1/auth.proto Package: qpc.v1 Method IDs: 100-103

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 for the server-side implementation and the full flow diagram.


Full proto listing

syntax = "proto3";
package qpc.v1;

// OPAQUE registration + login (4 methods).
// Method IDs: 100-103.

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;
}

Registration flow (IDs 100-101)

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)

Client                          Server
  |                                |
  |  OpaqueRegisterStartRequest    |
  |  username: "alice"             |
  |  request: <OPAQUE blob>        |
  | -----------------------------> |
  |                                |
  |  OpaqueRegisterStartResponse   |
  |  response: <OPAQUE blob>       |
  | <----------------------------- |

Request fields:

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.

Response fields:

Field Type Description
response bytes OPAQUE RegistrationResponse blob generated by the server. Client feeds this into the finish step.

OpaqueRegisterFinish (ID 101)

Client                          Server
  |                                |
  |  OpaqueRegisterFinishRequest   |
  |  username: "alice"             |
  |  upload: <OPAQUE record>       |
  |  identity_key: <32 bytes>      |
  | -----------------------------> |
  |                                |
  |  OpaqueRegisterFinishResponse  |
  |  success: true                 |
  | <----------------------------- |

Request fields:

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.

Response fields:

Field Type Description
success bool true if the registration record was stored successfully. false if the username is already taken or another error occurred.

Login flow (IDs 102-103)

User login also takes two round trips. On success, the server issues a session_token that the client attaches to subsequent authenticated RPCs.

OpaqueLoginStart (ID 102)

Client                          Server
  |                                |
  |  OpaqueLoginStartRequest       |
  |  username: "alice"             |
  |  request: <OPAQUE blob>        |
  | -----------------------------> |
  |                                |
  |  OpaqueLoginStartResponse      |
  |  response: <OPAQUE blob>       |
  | <----------------------------- |

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.


Session token usage

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.

The Auth message in common.proto carries the token for federation and internal use:

message Auth {
  bytes access_token = 1;
  bytes device_id = 2;
}

Further reading