aetheris-protocol 0.2.0

High-performance binary contracts and communication traits for the Aetheris Engine
Documentation
syntax = "proto3";
package aetheris.auth.v1;

service AuthService {
    // ── Email OTP path ──
    rpc RequestOtp(OtpRequest) returns (OtpRequestAck);

    // ── Unified Login path ──
    rpc Login(LoginRequest) returns (LoginResponse);
    rpc CreateGoogleLoginNonce(GoogleLoginNonceRequest) returns (GoogleLoginNonceResponse);

    // ── Session lifecycle (unchanged) ──
    rpc Logout(LogoutRequest) returns (LogoutResponse);
    rpc RefreshToken(RefreshRequest) returns (RefreshResponse);
    rpc IssueConnectToken(ConnectTokenRequest) returns (ConnectTokenResponse);
}

// ── Email OTP ──────────────────────────────────────────────────────

message OtpRequest {
    // RFC-5321-compatible email. Server normalizes (lowercase, trim).
    string email = 1;
}

message OtpRequestAck {
    // Opaque server-chosen handle for this OTP attempt.
    string request_id = 1;
    // Unix timestamp in milliseconds when the request expires.
    uint64 expires_at_unix_ms = 2;
    // populated if the email is rate-limited.
    optional uint32 retry_after_seconds = 3;
}

// ── Unified Login ──────────────────────────────────────────────────

message LoginRequest {
    oneof method {
        OtpLoginRequest    otp    = 1;
        GoogleLoginRequest google = 2;
    }
    ClientMetadata metadata = 3;
}

message ClientMetadata {
    string client_version = 1;
    string platform       = 2; // e.g., "wasm", "ios", "windows"
}

message OtpLoginRequest {
    string request_id = 1;
    string code       = 2;  // 6-digit numeric, ASCII "000000".."999999"
}

message GoogleLoginRequest {
    string google_id_token = 1;
    string nonce_handle    = 2; // Handle returned by CreateGoogleLoginNonce
}

message GoogleLoginNonceRequest {}
message GoogleLoginNonceResponse {
    string nonce_handle = 1;
    string nonce        = 2; // To be passed to Google OIDC by the client
    // Unix timestamp in milliseconds when the nonce expires.
    uint64 expires_at_unix_ms = 3;
}

// ── Shared response shape ──────────────────────────────────────────

message LoginResponse {
    string session_token = 1;
    // Unix timestamp in milliseconds when the session expires.
    uint64 expires_at_unix_ms = 2;
    string player_id     = 3;
    bool   is_new_player = 4;
    LoginMethod login_method = 5;
}

enum LoginMethod {
    LOGIN_METHOD_UNSPECIFIED = 0;
    LOGIN_METHOD_EMAIL_OTP = 1;
    LOGIN_METHOD_GOOGLE_OIDC = 2;
}

// ── Session lifecycle (unchanged) ─────────────────────────────────

message LogoutRequest  { string session_token = 1; }
message LogoutResponse { bool revoked = 1; }

message RefreshRequest  { string session_token = 1; }
message RefreshResponse {
    string session_token = 1;  // fresh PASETO; old token's jti added to deny-list
    // Unix timestamp in milliseconds when the session expires.
    uint64 expires_at_unix_ms = 2;
}

message ConnectTokenRequest {
    string session_token  = 1;
    string server_address = 2;  // "host:4433"
}

message ConnectTokenResponse {
    QuicConnectToken token = 1;
}

message QuicConnectToken {
    // PASETO v4.local, footer = key id (kid) for rotation, payload = claims below.
    string paseto             = 1;
    string server_address     = 2;
    uint64 expires_at_unix_ms = 3;
    uint64 client_id          = 4;  // u64, randomly assigned at issuance
}