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

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

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

    .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