← reports

#5706 · ACP authentication method selection

BugPriority: LowEffort: Mediumproviders · provider-acpIssue

2026-10-17 · trusted origin/main ee36dfda7815e8c72672ab57e2bdb1b395ada9be

Verdict: REPRODUCED · Root-cause confidence: high · reproduction label: confirmed-repro.

1. TL;DR

An ACP agent can advertise a method that it accepts, yet bb cannot start an authentication-gated session with it. Both ACP bridges select only two special method IDs; other IDs cause the authentication helper to return without making a request. The existing repository test agent reproduces this through the real bridge entry point, without running any issue-provided code. A recognized-method control succeeds, while a newly chosen opaque method fails with an authentication error. The same result was repeated from a second clean checkout by the same investigator.

2. Claims vs findings

ClaimFindingEvidence
Other advertised method IDs cannot authenticate a gated session.Verified at the bridge boundaryThe existing fake agent advertises workspace-session and accepts that method. Both real bridges fail to start a thread; the identical test with cached_token succeeds.
Both ACP implementations have the same selection restriction.VerifiedBoth production selectors and both reproduction runs show the restriction.
The original external agent and packaged release exhibit this behavior.Not independently tested hereNo external agent, linked branch, issue script, or original service was executed. The reproduction uses trusted main and its own committed fixture.
Protocol rules require a particular generic or interactive fallback.Not evaluatedExternal links from the issue were not fetched. This report establishes implementation behavior, not complete ACP specification conformance or a safe choice among multiple login methods.

3. Environment

4. Minimal reproduction

This is a bridge-level integration reproduction: the repository's real handleLine receives thread/start, launches its committed ACP fake agent, and executes the session setup path. It is not a standalone imitation of the authentication selector.

  1. Make a clean trusted checkout and install its existing dependencies:
    git clone https://github.com/get-bb/bb.git bb-5706
    cd bb-5706
    git checkout --detach ee36dfda7815e8c72672ab57e2bdb1b395ada9be
    pnpm install --frozen-lockfile --prefer-offline
    pnpm exec turbo run build --filter=@bb/provider-bridge-acp --filter=@bb/provider-bridge-acp-next

    These two source-only bridge packages do not define a build script, so the scoped build reports no tasks. Test tasks run through Turbo and its configured dependency graph.

  2. In each of packages/provider-bridge-acp/src/bridge/bridge.test.ts and packages/provider-bridge-acp-next/src/bridge/bridge.test.ts, replace the existing test named authenticates ACP sessions with cached tokens when advertised with this table-driven extension of that same test:
      it.each(["cached_token", "workspace-session"])(
        "authenticates advertised ACP method %s",
        async (methodId) => {
          const { providerThreadId } = await startThread({
            envVars: { FAKE_ACP_AUTH_METHODS: methodId },
          });
    
          const turnId = sendTurnRequest("turn/start", providerThreadId, {
            input: [{ type: "text", text: "echo-auth-method", mentions: [] }],
          });
          await waitForResponse(turnId);
          await waitForTurnCompleted();
    
          expect(agentMessageTexts()).toContain(`auth-method:${methodId}`);
        },
      );

    No production code or fake-agent implementation changes are required. The advertised method type is omitted, just as it is in the existing fixture. The agent accepts any method ID from its advertised list and gates session creation on a successful authentication request.

  3. Run the two package tests separately so a failure in one does not cancel the other:
    pnpm exec turbo run test --filter=@bb/provider-bridge-acp -- src/bridge/bridge.test.ts -t 'authenticates advertised ACP method'
    pnpm exec turbo run test --filter=@bb/provider-bridge-acp-next -- src/bridge/bridge.test.ts -t 'authenticates advertised ACP method'

Expected: both methods can start a session and complete the echo turn; each package has two passing cases. Actual: the known method succeeds; the opaque method fails during thread startup, before the echo assertion. Selected verbatim output:

@bb/provider-bridge-acp:test: Error: thread/start failed: Authentication required
@bb/provider-bridge-acp:test:       Tests  1 failed | 1 passed | 141 skipped (143)

@bb/provider-bridge-acp-next:test: Error: thread/start failed: Authentication required. The agent offers these ways to sign in: Sign in (workspace-session). Sign in with the agent's own command on the machine that hosts the thread, then try again.
@bb/provider-bridge-acp-next:test:       Tests  1 failed | 1 passed | 177 skipped (179)

The command exit status is 1 as expected for this failing regression. No fix was applied, so no post-fix pass is claimed. All reproduction code and relevant output are embedded here; raw checkout logs and test patches stay outside the public reports repository.

5. Root cause

The original bridge's method selector and authentication helper only choose xai.api_key when its environment key exists, otherwise cached_token when advertised. Any other method produces undefined and the helper immediately returns:

if (env.XAI_API_KEY && methodIds.has("xai.api_key")) {
  return "xai.api_key";
}
if (methodIds.has("cached_token")) {
  return "cached_token";
}
return undefined;

if (methodId === undefined) {
  return;
}

The next bridge has the same selection and early return. The original bridge calls the helper after initialization at session setup, then sends session/new. The next bridge follows the corresponding initialization/authentication and session creation path.

The committed original fake agent's authentication gate rejects unauthenticated sessions with ACP error -32000. Its authenticate handler accepts any advertised ID, so the opaque ID is not itself an agent rejection. The special-ID control validates the working transport/session/turn path.

Existing coverage explicitly expects unsupported advertised methods to surface the agent's authentication error. That explains why existing tests pass despite the interoperability limitation, and makes changing generic authentication behavior a policy change rather than a safe mechanical replacement. A signed-in agent that does not require protocol authentication is outside the failing case. Session restoration and discovery share the helper but were not separately reproduced here.

6. Proposed fix and safety decision

Define the supported behavior for protocol-driven methods and method selection first. A follow-up can add a bounded, explicit authentication-required recovery path in both bridges, respecting method types and preserving existing special-ID handling. It must not blindly pass terminal methods to the protocol authentication RPC or initiate interactive login simply because a method was advertised. Cover single and multiple methods, optional authentication, terminal-only methods, rejected login, bounded retries, and session restoration.

No pull request was opened: the autopilot's simple-fix rules explicitly exclude authentication changes. This issue necessarily changes authentication behavior, and the current unknown-method behavior has intentional coverage. The local reproduction is test-only: 50 added-plus-deleted lines across two files; zero production changes. Its small size does not waive the authentication exclusion. No source branch was pushed.

7. Pull request metadata

No open pull request in get-bb/bb was found linked to issue 5706, and an open-PR search for the issue number was empty. Timeline metadata contains a reference from a different repository; its code and branch were not fetched or run. It is not evidence of a bb-side repair and no review of external code is claimed.

8. Related issues

Nearby ACP issue metadata was checked for labeling patterns. No related issue was executed or treated as proof of this authentication defect. No duplicate was established.

9. Verification

The same investigator created a second detached worktree at the recorded trusted commit, verified it was clean, repeated the frozen install and scoped build, and applied only the same test-table extension. Tests used new automatically created temporary workspaces and agent processes; there were no ports or persistent data directories to reuse. This is a second clean reproduction, not an independent reviewer check.

RunOriginal bridgeNext bridge
First checkout, focused regression1 failed / 1 passed1 failed / 1 passed
Second clean checkout, focused regression1 failed / 1 passed1 failed / 1 passed
Unchanged existing authentication-related tests in second checkout6 passed8 passed

The first run invoked both package filters together. In the second run Turbo stopped the combined command after the original bridge failure; the next bridge was then run separately and produced the same intended failure. No report conclusion changed. Formatting and git diff --check passed; both checkouts contain identical test edits. No binary changes, dependency changes, or production modifications were made.

10. Appendix and limits

The unchanged baseline checks used:

pnpm exec turbo run test --filter=@bb/provider-bridge-acp --filter=@bb/provider-bridge-acp-next -- src/bridge/bridge.test.ts -t 'auth|sign in'

@bb/provider-bridge-acp:test:       Tests  6 passed | 136 skipped (142)
@bb/provider-bridge-acp-next:test:       Tests  8 passed | 170 skipped (178)

The reproduction is nonvisual, so no screenshot is appropriate. This report does not claim to reproduce the reporter's OS, release tarball, external agent build, or complete server/UI journey. Confidence is high for the shared bridge selection mechanism and its observable startup failure.

Untrusted-data note: the issue's proposed scripts, fixes, commands, links, and external branch were treated only as untrusted claims. None were executed or fetched. The reproduction was derived from trusted main's existing bridge tests and fake agents, using a newly chosen method ID.