Skip to content

Identity & Authentication

mzchat uses a hierarchical cryptographic identity model rooted in Ed25519 keypairs. This ensures that a user’s identity is permanent and portable across servers, while allowing individual devices to be revoked or rotated.

The Root Identity is the canonical, permanent identifier for a user.

  • Permanent ID: The Ed25519 public key of $K_{id}$ is the user’s immutable ID network-wide.
  • Security: $K_{id}$ is never used for daily chat operations. Its sole purpose is to sign Device Certificates.
  • Portability: By importing the $K_{id}$ seed, a user can authorize new devices on any server without losing their global identity.

Every device generates its own ephemeral Ed25519 keypair.

  • Access Control: Active network access is granted via a Device Certificate ($Cert_{dev}$), which is a statement signed by $K_{id}$ binding a $K_{dev}$ public key to a user ID for a specific duration.
  • Hardware Isolation: $K_{dev}$ never leaves the device’s secure storage.

On mobile platforms, mzchat leverages the system’s secure enclave (Keychain on iOS, Keystore on Android) to protect sensitive identity data.

Users can opt-in to Biometric Security, which adds an additional layer of protection:

  • Enclave Storage: The $K_{dev}$ secret key and $K_{id}$ (if present) are stored in the system’s hardware-backed secure storage.
  • Access Control: Retrieval of these keys requires user authentication via Fingerprint, Face ID, or system PIN.
  • Protection: This ensures that even if the mobile operating system is compromised, the cryptographic identity of the user remains inaccessible without physical user presence.

Authentication follows a three-step cryptographic validation:

  1. Request Signature: The client signs a challenge (e.g., a timestamp) using its local $K_{dev}$.
  2. Certificate Binding: The client attaches the $Cert_{dev}$ signed by $K_{id}$.
  3. Root Validation: The server verifies that the $Cert_{dev}$ is validly signed by the $K_{id}$ corresponding to the User.id, and that the request signature matches the public key embedded in the certificate.

This model allows for Offline Revocation: if a device is lost, the user can sign a revocation statement with $K_{id}$ that servers use to immediately invalidate the $Cert_{dev}$.

Session state relies on synchronization between the issued JWT and the server’s current permission state.

A token becomes stale whenever a user’s guild membership or role assignments change (e.g., after JoinInvite or CreateGuild).

  • Protocol: RPCs that modify authorization state return a new JWT.
  • Requirement: Clients must immediately replace their stored auth_token with the one returned in the response to ensure subsequent actions have the correct permissions.

The real-time event stream (SubscribeEvents) is authorized at the moment of connection.

  • Requirement: If the authentication state changes (new token), the client must abort and restart the event stream. The server does not dynamically update permissions for an established stream.

To support long-lived sessions while keeping access tokens short-lived (e.g., 24 hours), mzchat uses Refresh Tokens.

  • Issuance: Upon Register, Login, or JoinInvite, the server returns a refresh_token alongside the token.
  • Storage: Clients must store the refresh_token securely (e.g., localStorage).
  • Usage: When an API request fails with Unauthenticated, the client attempts to use the Refresh RPC with the refresh_token to obtain a new access token.
  • Rotation: The Refresh RPC rotates the refresh token. The client must replace the old refresh token with the new one returned in the response.
  • Revocation: Refresh tokens are stored in the database and can be revoked by deleting the corresponding row. They are linked to a user and device ID.