Skip to content

Custom Engine Agent: Magic code / verification code popup appears in Copilot Chat but not in Teams direct chat when using third-party OAuth (Generic OAuth 2) connection #437

@rakshithvikramraj-loopio

Description

Summary

We are building a Custom Engine Agent for Microsoft 365 Copilot using the @microsoft/agents-hosting SDK (Node.js/TypeScript). The agent authenticates users via a third-party OAuth 2.0 provider (not Entra ID) configured as a Generic OAuth 2 connection in Azure Bot Service.

The issue: During sign-in, the Bot Framework opens a popup for the user to authenticate with the third-party provider. After the user completes authentication:

  • In Teams direct chat (1:1): The popup closes automatically and the signin/verifyState invoke is relayed back to the bot silently. The user never sees or copies a magic code.
  • In Microsoft 365 Copilot Chat: The popup shows a 6-digit magic/verification code and asks the user to manually copy and paste it into the chat window to complete sign-in.

This creates a poor user experience in Copilot Chat specifically.

Environment

  • SDK: @microsoft/agents-hosting v1.0.0 (Microsoft 365 Agents SDK for Node.js)
  • OAuth Connection: Generic OAuth 2 (third-party provider, not Entra ID)
  • Manifest version: 1.24
  • Agent type: Custom Engine Agent (copilotAgents.customEngineAgents)
  • Channels affected: Microsoft 365 Copilot Chat only
  • Channels working correctly: Teams personal chat (1:1)

What We've Tried

  1. Added webApplicationInfo to the Teams app manifest with api://botid-{BOT_ID} — no effect (expected, since SSO token exchange only works with Entra ID).

  2. Set enableSso: false on the OAuth handler configuration — this correctly prevents the SDK from attempting SSO token exchange (which always fails for non-Entra ID providers), but the magic code popup still appears.

  3. Fixed the invoke activity handler to skip signin/* activities so the SDK's authorization manager can process signin/tokenExchange and signin/verifyState properly.

  4. Confirmed Entra ID app registration is correctly configured with Application ID URI, exposed API scope, and pre-authorized Teams/Copilot client IDs.

What We Understand

From the Microsoft documentation:

  • SSO token exchange (signin/tokenExchange) only works with Microsoft Entra ID as the OAuth service provider (source).
  • The Token Exchange URL field in Azure Bot OAuth Connection Settings is documented as "used for SSO in Microsoft Entra ID only" (source).
  • For third-party OAuth providers, the tokenPostResource.sasUrl mechanism exists in the OAuthCard, but it appears to only be supported in custom canvas apps via Direct Line, not in the Teams/Copilot chat client (source).

Questions

  1. Is there a planned improvement for the Copilot Chat client to automatically relay signin/verifyState for third-party OAuth providers (similar to how Teams direct chat handles it), eliminating the need for users to manually copy/paste the magic code?

  2. Is there a supported pattern for Custom Engine Agents using @microsoft/agents-hosting to achieve seamless authentication with a third-party OAuth provider in Copilot Chat without the magic code prompt?

  3. Does the tokenPostResource.sasUrl mechanism work in the Teams/Copilot Chat client, or is it limited to custom canvas / Direct Line scenarios? If it works, what configuration is needed to enable it?

  4. As a workaround, would configuring an Entra ID OAuth connection (for SSO) alongside a separate third-party OAuth connection (for the actual API access) be a supported pattern? If so, are there any samples or documentation for this dual-connection approach?

Relevant Code

Auth handler configuration (config.ts):

return {
  loopio: {
    name: this.oauthConnectionName!,
    text: this.authSignInText,
    title: this.authSignInTitle,
    enableSso: false, // Third-party OAuth — SSO token exchange only works with Entra ID
  },
};

Manifest (manifest.json):

{
  "copilotAgents": {
    "customEngineAgents": [{ "type": "bot", "id": "${{BOT_ID}}" }]
  },
  "bots": [{ "botId": "${{BOT_ID}}", "scopes": ["copilot", "personal", "team"] }],
  "webApplicationInfo": {
    "id": "${{BOT_ID}}",
    "resource": "api://botid-${{BOT_ID}}"
  }
}

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions