Skip to content

provider-acp only calls ACP authenticate for method ids cached_token and xai.api_key; agents that advertise any other id fail with "Authentication required" #5706

Open

Description

@djbclark

Summary

When an ACP agent advertises an auth method with any id other than cached_token or xai.api_key, bb never calls authenticate. If the agent refuses session/new until it has been authenticated (ACP auth_required, code -32000), every thread on that agent ends with "Authentication required: ...". The ACP authentication page says a client calls authenticate with an advertised method ID when the agent requires authentication, and that a method with no type is the default type agent (agent-handled, protocol-driven). Crush's ACP server (charmbracelet/crush PR #2450) is one such agent: it advertises one method, local.

Versions and environment

  1. bb 0.46.1 (bb-app from the npm tarball, run as a service on NixOS x86_64), Node 24. Same code on main at ee36dfd.
  2. Custom ACP agent (customAgents in the provider-acp plugin): Crush crush acp built from PR Split right-panel panes have no close action when their only tab is fixed #2450 (plus unrelated local commits), initialize answers authMethods: [{"id":"local","name":"Local","description":"Authenticate the local ACP client session"}] and session/new returns -32000 authenticate before creating or loading sessions until authenticate has been called.
  3. Both adapters have the same code: provider-acp and provider-acp-next.

Steps to reproduce

Closest faithful repro without Crush: a 20-line agent that advertises one agent-type method and gates session/new on authenticate. I ran the script standalone (initialize, then session/new fails; initialize, authenticate local, session/new succeeds). I did not re-run it through a bb server in exactly this form; the same failure was observed with Crush through bb, so mark this as unverified for the minimal agent.

  1. Save as /tmp/auth-gated-agent.mjs:
#!/usr/bin/env node
import readline from "node:readline";
let authenticated = false;
const send = (m) => process.stdout.write(JSON.stringify({ jsonrpc: "2.0", ...m }) + "\n");
readline.createInterface({ input: process.stdin }).on("line", (line) => {
  const msg = JSON.parse(line);
  if (msg.id === undefined) return;
  switch (msg.method) {
    case "initialize":
      return send({ id: msg.id, result: { protocolVersion: 1, agentCapabilities: {}, authMethods: [{ id: "local", name: "Local" }] } });
    case "authenticate":
      authenticated = true;
      return send({ id: msg.id, result: {} });
    case "session/new":
      if (!authenticated) return send({ id: msg.id, error: { code: -32000, message: "authenticate before creating or loading sessions" } });
      return send({ id: msg.id, result: { sessionId: "s1" } });
    default:
      return send({ id: msg.id, error: { code: -32601, message: "method not found" } });
  }
});
  1. bb plugin config provider-acp set customAgents '[{"id":"authgated","displayName":"Auth gated","command":"node","args":["/tmp/auth-gated-agent.mjs"]}]'
  2. bb thread spawn --project <any project> --provider acp-authgated --prompt "Reply only with ok."

Did not reproduce with: any agent that advertises cached_token (the bridge's own fake agent covers this), or that does not gate session/new on authenticate.

Expected vs actual

Actual (Crush through bb 0.46.1, before any workaround): the thread ends in error

Authentication required: authenticate before creating or loading sessions

and the bridge sent no authenticate request at all (it returns silently when no advertised id matches). Expected: bb calls authenticate with the advertised local method, then session/new succeeds.

Evidence

  1. The id choice: resolveAcpAuthMethodId returns xai.api_key (when XAI_API_KEY is set), else cached_token, else undefined. authenticateAcpAgent returns early on undefined. Call sites: L899 and L1874.
  2. Same in the rebuilt adapter: provider-bridge-acp-next L781-L822.
  3. Neither id is documented: neither cached_token nor xai.api_key appears in docs/ (the Custom ACP Agents section of docs/configuration.md does not mention authentication).
  4. Confirmation from the other side: adding cached_token as an alias of local in the Crush server (a 5-line patch) makes the same thread start and authenticate (it then stops only because no model provider is configured). Checked at the protocol level too, with a throwaway provider: initialize, authenticate cached_token, session/new all answer.
  5. ACP spec: https://agentclientprotocol.com/protocol/v1/authentication ("The default authentication method type is agent ..."; "When an Agent requires authentication and the selected method uses the protocol-driven flow, the Client calls authenticate with the advertised authentication method ID"; terminal-type methods must not be passed to authenticate).

What you ruled out

  1. Not provider.list_models startup probe logs "ACP agent is not authenticated." at warn on every daemon start #2291 (a warn line at daemon start; here the thread fails) and not Pi fails to initialize with custom llama-server model URL (Hermes3.6-35B-A3B GGUF) - suspected acp-provider auth handshake issue #3911 (Pi with a custom llama-server URL; no id analysis there, I cannot tell whether it is the same cause).
  2. Not a Crush-only bug: Crush's server is spec-conformant here, which is why a client-side fix is wanted. A server-side alias works as a workaround but only for agents one controls.
  3. Still the same on main at ee36dfd.

Suggested priority and effort

Low priority, low effort: affects only custom ACP agents with a non-standard auth id, workaround exists only for agents you can patch. Two fix ideas:

  1. Lazy and generic: if session/new (or session/load) fails with auth_required and the agent advertised methods of type agent (no type, never terminal), call authenticate once with the first such method (or the only one) and retry the request once. Doing it lazily avoids starting an interactive login for agents that would not have needed one.
  2. Explicit: an optional authMethodId on a customAgents entry (the schema already carries per-agent knobs such as permissionCli), used in place of the built-in two ids when set.
    Either way, document the two built-in ids in the Custom ACP Agents section.

AGENT GENERATED

Activity

  1. added theissue type on Oct 17, 2026
  2. added
    providersCross-provider bridges, models, login
    provider-acpBuilt-in plugin: provider-acp
    confirmed-reproBug reproduced again from a clean trusted checkout; see linked report
    on Oct 17, 2026
  3. bb-slop-cop commented on Oct 17, 2026

    @bb-slop-cop
    Contributor

    🚨 SLOP COP 🚨 · new-issue-autopilot

    • Classification: Bug · Priority: Low · Effort: Medium.
    • Labels: providers, provider-acp, confirmed-repro.
    • Report: https://get-bb.github.io/reports/issues/5706.html — REPRODUCED, high root-cause confidence.
    • Root cause: Both ACP bridges select only special authentication method IDs and skip authentication for other advertised IDs, so authentication-gated sessions cannot start.
    • Verification: The focused bridge regression fails for an opaque method and passes for the recognized-method control in two clean trusted checkouts; all 14 existing authentication-related checks pass. The external agent itself was not run.
    • No PR: Changing authentication behavior is explicitly excluded by this rule's simple-fix criteria.
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

    confirmed-reproBug reproduced again from a clean trusted checkout; see linked reportprovider-acpBuilt-in plugin: provider-acpprovidersCross-provider bridges, models, login

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions