Skip to content

.NET: [Bug]: Hosted agent toolbox consent link is bound to the container's managed identity, so sign-in fails with "Code <id> not found" #8379

Closed

Description

Description

When a hosted agent uses a pre-registered toolbox with a per-user OAuth MCP connection, the consent link in its oauth_consent_request can't be completed. Signing in ends on /nextgen/closeMe with Something went wrong while authenticating. Error: Code <id> not found.

The callback's userCtx has userId set to the project's system-assigned managed identity, not the user who called the agent. The container authenticates to the toolbox proxy with that identity (the MSAL log shows the system_assigned_managed_identity token cache), so the proxy creates the consent session for it. The inbound request did carry the user: the container log shows HasUserId=True HasCallId=True.

The call id should reach the proxy too. AgentFrameworkResponseHandler re-applies HostedCallContext.CallId before toolbox egress, and FoundryToolboxBearerTokenHandler forwards it as x-agent-foundry-call-id "so the toolbox proxy can resolve the server-side caller context".

Credential lookup does follow the calling user. When the same user calls the toolbox MCP endpoint directly with their own token, tools/list returns -32006 with a link bound to them, and sign-in succeeds. The agent's next request then lists and calls the toolbox tools with that user's credential. A principal that never signed in still gets CONSENT_REQUIRED. Only the link produced on the hosted path is bound to the wrong identity.

Steps to reproduce:

  1. Create a project connection with custom OAuth2 (an Entra app with a delegated scope) to a remote MCP server, and a toolbox that references it.
  2. Host an agent that calls AddFoundryToolboxes(new DefaultAzureCredential(), "<toolbox>") on the Responses protocol 2.0.0, and deploy it.
  3. Call the agent endpoint with a user's Entra token. The response is incomplete with an oauth_consent_request.
  4. Open the consent link and sign in as that user.

Expected: the sign-in is stored for the calling user, and resending the request runs the tool.

Actual: sign-in fails with the error above, and every later request returns a new link bound to the managed identity.

Code Sample

var credential = new DefaultAzureCredential();
var agent = new AIProjectClient(projectEndpoint, credential)
    .AsAIAgent(model: deploymentName, instructions: instructions, name: "orchestrator");

var builder = AgentHost.CreateBuilder(args);
builder.Services.AddFoundryResponses(agent);
builder.Services.AddFoundryToolboxes(credential, toolboxName);
builder.RegisterProtocol("responses", endpoints => endpoints.MapFoundryResponses());
builder.Build().Run();

Error Messages / Stack Traces

Something went wrong while authenticating. Please close this window and try again.
Error: Code <id> not found.
closeMe userCtx (decoded): {"userId":"<project managed identity object ID>","tenantId":"<tenant>","connectionName":"<connection>.<id>.<id>","projectUrl":"<project endpoint>"}

Package Versions

Microsoft.Agents.AI.Foundry.Hosting: 1.21.0-preview.260911.1, Azure.AI.Projects: 3.0.0-beta.2, Azure.Identity: 1.21.0

.NET Version

.NET 10.0 (Linux x64 container, runtime 10.0.12)

Additional Context

Follows #6562, which made the consent link visible (fixed in #6718). ToolboxOAuthConsentHostedAgentTests is skipped on main, and it only asserts that a consent link is returned, so completing consent isn't covered.

Our workaround is taking the consent link from a direct toolbox tools/list call made with the user's token.

Activity

  1. added
    .NETUsage: [Issues, PRs], Target: .Net
    triageUsage: [Issues], Target: All issues that still need to be triaged
    on Sep 14, 2026
  2. added
    needs-maintainer-triageUsage: [Issues], Target: all issues that the automated triage flow failed to process
    on Sep 14, 2026
  3. joshua-lehmann commented on Oct 14, 2026

    @joshua-lehmann

    We hit a closely related case, and it blocks us. A .NET hosted agent can't use per-user (delegated) OAuth toolbox tools, so MAF hosted agents don't work for our scenario: Microsoft 365 Copilot connector retrieval with per-user security trimming, where app-only Graph access isn't an option.

    Our setup differs from the original report in two ways, both making things worse:

    Setup

    • The toolbox has an OpenAPI tool (not MCP) that calls Microsoft Graph POST /v1.0/copilot/retrieval (dataSource: externalItem). Auth is type: project_connection with a custom OAuth2 connection (delegated ExternalItem.Read.All, admin consented).
    • Tool search is enabled, so the agent sees tool_search and call_tool. The same toolbox also has an unauthenticated MCP tool (Microsoft Learn MCP).
    • The host uses AddFoundryResponses(agent) with AddFoundryToolboxes(new DefaultAzureCredential(), "<toolbox>"), Responses protocol 2.0.0, deployed with azd. The container log shows HasUserId=True HasCallId=True.

    Observed

    1. No oauth_consent_request reaches the client at all. call_tool → graph-retrieval___SearchInternalKnowledge fails with McpProtocolException -32006. The exception goes to the model as a generic function error and the response completes, so the model replies "no results". Going by the source, ConsentAwareMcpClientAIFunction should turn -32006 into oauth_consent_request, but that doesn't happen here. The cause may be the call_tool wrapper or the OpenAPI tool type.
    2. The direct-call workaround doesn't help us. As the same user, I called the toolbox MCP endpoint directly (tools/call → call_tool) with my own https://ai.azure.com token and got -32006 with a consent link. I opened it and signed in. The page showed Error: Code <id> not found., yet consent was stored: repeating the direct call now returns Graph retrievalHits. But the hosted agent, invoked by the same user right afterwards, still fails with -32006 on every call. Here, consent made through the direct path is not used by the hosted path.
    3. The unauthenticated Learn MCP tool in the same toolbox works through call_tool in the same session. Discovery works too (Toolbox '<toolbox>': discovered 3 tool(s).).

    Container log (diagnostic middleware; this also happened before the middleware was added)

    ToolInvocation: name=tool_search status=returned
    ToolInvocation: name=call_tool status=failed exception=ModelContextProtocol.McpProtocolException rpcCode=-32006
    ToolInvocation: name=call_tool status=failed exception=ModelContextProtocol.McpProtocolException rpcCode=-32006
    

    Versions

    • Microsoft.Agents.AI.Foundry and Microsoft.Agents.AI.Foundry.Hosting 1.22.0-preview.260918.1; the same behaviour reproduces on 1.24.0-preview.261006.1.
    • .NET 10.0 (net10.0, Linux container); Foundry region West Europe.

    Expected

    • -32006 from a toolbox tool, including one called via tool search call_tool and including OpenAPI tools, should produce an oauth_consent_request bound to the calling user.
    • Once that user has consented, by any path, the hosted agent should run the tool with that user's delegated token.

    Related: #6562 / #6718, #7743. I'm happy to provide more traces privately (session IDs, trace IDs) if that helps.

    Roger Barreto (@rogerbarreto) Is there a planned fix for that?

  4. rogerbarreto commented on Oct 18, 2026

    @rogerbarreto
    Member

    Joshua Lehmann (@joshua-lehmann) Thanks for the information, please any tracing data and reproduction code you can provide would be helpful to try reproduce the issue in our end.

    We have tried previously to reproduce the issue without any conclusive results (wasn't able to reproduce). Any consistent repro problem and infrastructure that you can provide will help to undertand what can be addressed from MAF or within Toolbox AuthE.

    Thanks!

  5. joshua-lehmann commented on Oct 19, 2026

    @joshua-lehmann

    Roger Barreto (@rogerbarreto) Thanks, I attached is a minimal reproduction ZIP with source, deployment/toolbox configuration, exact HTTP/SSE and persisted responses, both session-log downloads, and correlated Application Insights traces. Credentials and OAuth consent state are excluded/redacted.

    Freshly reproduced on 2026-10-19, West Europe, .NET 10 / Responses 2.0.0 / MAF 1.25.0-preview.261014.1, using a separate hosted agent with only the delegated Graph OpenAPI tool and tool search:

    • tool_search succeeds; call_tool invokes graph-retrieval___SearchInternalKnowledge once and throws -32006 / FailedPrecondition with a consent URL.
    • The client receives HTTP 200 / response.completed, tool output Error: Function failed., and no oauth_consent_request. Exact assistant reply: “The internal knowledge search failed.”
    • Verified trace IDs: c58985c537a816cbd41da7a69a859d9c (~06:50 UTC) and b6d8b85fef6e4197b0f700e9c929d0a7 (~06:53 UTC). The ZIP includes session/response/APIM/tool-call IDs and full error stacks.

    This isolates the missing consent handoff through call_tool. Could you investigate this OpenAPI + tool-search path? If you need any more details, let me know or contact me directly. Thanks for your support.

    oauth-8379-evidence-2026-10-19.zip

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

Metadata

Metadata

Labels

.NETUsage: [Issues, PRs], Target: .Netneeds-maintainer-triageUsage: [Issues], Target: all issues that the automated triage flow failed to processtriageUsage: [Issues], Target: All issues that still need to be triaged

Type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions