Skip to content

feat(auth): persist tenant-scoped Codex session affinity #5

Description

@zendext

Requirement

Add session-sticky auth selection for multi-auth operation and persist bindings in the existing SQLite database so an active Codex conversation keeps the same OAuth account across proxy restarts.

Decisions

  • Bind one logical Codex session to one auth independently of model name.
  • Scope managed-client bindings by (user_id, session_key) so tenants cannot collide and API-key rotation preserves affinity.
  • For compatibility routes authenticated by a currently loaded Codex access token, scope affinity by the matched stable auth identity.
  • Accept only explicit bounded session signals: Session-Id/Session_id, body session_id/sessionId, prompt_cache_key, and conversation.id/conversation_id.
  • Do not infer sessions from message content, client IP, request hashes, or generated request IDs.
  • Treat prompt-cache and conversation identifiers as aliases when both identify the same logical session.
  • Use a sliding expiration, bounded storage, and expired-row cleanup; bindings survive restarts but not auth removal or identity replacement.
  • Keep a healthy binding; when the auth is unavailable, select another healthy auth and persist the new binding only after the replacement attempt succeeds.
  • Support one active COP process per database/auth directory.

Acceptance Criteria

  • Repeated requests with the same tenant and session identifiers select the same healthy auth across process restarts.
  • The same session ID used by different users cannot share or overwrite a binding.
  • Changing models within a session does not change the auth binding by itself.
  • API-key reset for a user does not discard that user's existing session bindings.
  • Missing explicit session identity falls back to normal healthy-auth round-robin selection without creating a binding.
  • Invalid, oversized, or control-character session identifiers are rejected as affinity keys without failing the proxied request.
  • Auth removal, stable identity change, expiry, and successful failover cleanly invalidate or replace affected bindings.
  • SQLite migration, lookup, upsert, renewal, cleanup, restart, alias, and tenant-isolation behavior have regression tests.

Non-goals

  • Model-scoped affinity keys.
  • Content-derived session identity.
  • Multi-process or distributed session coordination.
  • A separate JSON state file or external database service.

Dependencies

Verification

  • gofmt -w .
  • go test ./...
  • go build -o test-output ./cmd/server && rm test-output

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions