Skip to content

[Feature]: Keep one OAuth account from serving sessions on several machines at once #7801

Open

Description

@vibewriter-hand

Area

Authentication and account pool

What are you trying to accomplish?

Stop one OAuth account from being used by sessions on several machines at the same time. Two cases matter to us:

  1. One OpenCodex instance serves clients on several machines (for example a laptop forwards its port to a second PC over SSH). Requests from both machines reach the same pool and can land on the same account at once.
  2. Independent OpenCodex instances on two machines pick the same account at once.

What prevents this today?

For case 1, conversation affinity binds a conversation to an account, but nothing stops two conversations from different client machines from being bound to the same account at the same time. The pool does not know which machine a request came from. For case 2, each instance keeps its own pool selection and cooldown state, and independent instances have no shared lease. A first-party client that does not use OpenCodex cannot take part in a lease. Our concern is that one account used from several machines at once may look like account sharing to the provider and raise suspension risk; we have no measurement of provider behavior.

What should OpenCodex do?

For case 1, offer an opt-in per-provider rule: an account serves sessions from one client machine at a time. The client machine could be identified by a configured client label or header. A request from a second machine would get another eligible account, or a clear refusal when none is free. For case 2, consider an optional shared lease, or a supported coordination interface, with bounded expiry, owner identity, renewal, crash recovery and fencing. Define clearly what happens with clients that cannot take part.

Example usage or interface

Case 1: machine A and machine B both send requests through one instance with different client labels. While A holds account 1, B is given account 2. Case 2: two instances share a lease store. One claims an account; the other selects a different eligible account. A first-party client is protected only if it takes part or an operator reserves its account.

Alternatives or workarounds

Assign a distinct account to each instance and keep the split by hand.

Additional context

This is a proposed contract. We do not claim that an external client can be locked without its cooperation. On 2026-10-27 we searched issues and PRs for lease, multiple instances and multi-device and found no duplicate. Related: #5157 adds a writer lease for the spend journal in one state directory; #6077 proposed a single cloud container writer. Neither is a per-account lease across independent instances.

Checks

  • I searched existing issues and documentation.
  • This request describes a concrete OpenCodex workflow rather than merely naming a desired technology.
  • I removed secrets and personal data.

Activity

  1. lidge-jun commented on Oct 28, 2026

    @lidge-jun
    Owner

    On dev fdc6dd82d930295880dcf6d10bbb9f2c61994574, generic OAuth affinity stores conversation-to-account bindings in a process-local map (src/oauth/generic-session-affinity.ts:14, binding at :113). Its identity inputs are client/thread/session/cache keys (src/oauth/session-affinity-key.ts:4), not an authenticated machine owner. Kiro's existing capacity leases count requests per provider/account (src/oauth/kiro-account-load.ts:19); they do not express machine exclusivity. Neither merged #5157's state-directory writer lease nor closed #6077's container-writer proposal supplies the requested per-account coordination.

    Three options have different guarantees:

    • Keep distinct accounts assigned to instances manually. This is immediately usable and needs no lease service, but operators maintain the partition and it does not distinguish clients sharing one proxy.
    • Add single-instance account ownership by a configured client-machine identity, with several conversations from that owner allowed concurrently. Competing owners select another eligible account or receive a bounded refusal. This addresses case 1 without claiming cross-instance protection.
    • Add an optional shared coordinator for case 2. Atomic acquire/renew/release, incarnation fencing and partition behavior are necessary; it adds deployment and availability costs and still cannot constrain nonparticipating first-party clients.

    I recommend the second option first, behind a per-provider opt-in, then reuse its ownership contract if a coordinator is approved. Bind configured machine identities to dedicated authenticated client keys. src/server/auth-cors.ts:436 already distinguishes configured-key admission from anonymous loopback, but SSH-forwarded loopback traffic does not acquire a machine identity by itself. An arbitrary label/header or source IP should not be treated as proof of ownership. Under the opt-in, missing identity must have a documented refusal or explicitly configured shared-owner mode.

    Ownership should survive gaps between requests according to a declared idle lifetime, retain active-request references, and release only after the old owner's requests drain. Merely expiring a timestamp while an upstream send continues would permit the very overlap this feature promises to prevent. Re-login and duplicate provider rows also need a stable physical-account identity, rather than independent leases per local slot.

    There is no clearly safe implementation slice yet: first settle identity provisioning, session ownership lifetime and drain/expiry behavior. Then introduce a small ownership module at final credential admission, initially for one named provider. Proposed tests beside tests/oauth/generic-session-affinity.test.ts should prove same-owner sharing, competing-owner exclusion, unknown-owner refusal, cancellation/drain, credential replacement and expiry without overlapping live sends. This is source analysis; no provider suspension behavior or runtime result is claimed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    account-poolOAuth, credentials, Codex pool, quota, failover, plansenhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions