Fix SSO+OBO flow for declarative agents: correct identifierUris, add missing redirect URIs, surface OBO diagnostics#15786
Draft
Fix SSO+OBO flow for declarative agents: correct identifierUris, add missing redirect URIs, surface OBO diagnostics#15786
Conversation
… identifierUris, add redirect URIs Agent-Logs-Url: https://github.com/OfficeDev/microsoft-365-agents-toolkit/sessions/b88f930d-aad3-4922-9191-d1d66283e283 Co-authored-by: HuihuiWu-Microsoft <73154171+HuihuiWu-Microsoft@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix SSO and OBO flow for Declarative Agents calling Microsoft Graph
Fix SSO+OBO flow for declarative agents: correct identifierUris, add missing redirect URIs, surface OBO diagnostics
Apr 23, 2026
|
Below is a single, pastable setup: m365agents.yml + openapi.yaml +
aad.manifest.json aligned and wired to the backend
…------------------------------
setup (FiGraph OBO Proxy)
# =========================
# m365agents.yml
# =========================
version: 1.8
provision:
- uses: aadApp/create
with:
name: FiGraph-OBO-Proxy
- uses: aadApp/update
with:
manifestPath: aad.manifest.json
- uses: oauth/register
with:
name: FiGraph-OBO-Auth
identityProvider: MicrosoftEntra
clientId: ${{AAD_APP_CLIENT_ID}}
scopes:
- api://${{AAD_APP_CLIENT_ID}}/access_as_user
deploy:
- uses: apiSpec/register
with:
name: FiGraph-OBO-API
specPath: ./openapi.yaml
# =========================
# openapi.yaml
# =========================
openapi: 3.0.1
info:
title: FiGraph OBO Proxy
version: 1.0.0
description: OBO proxy API that calls Microsoft Graph via backend
servers:
- url: https://your-api.com # <-- replace with your backend URL
paths:
/messages:
get:
operationId: getServiceMessages
summary: Get Microsoft Graph service announcement messages
security:
- oauth2: [access_as_user]
responses:
'200':
description: Successful response
components:
securitySchemes:
oauth2:
type: oauth2
flows:
authorizationCode:
authorizationUrl:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize
tokenUrl: https://login.microsoftonline.com/common/oauth2/v2.0/token
scopes:
api://${{AAD_APP_CLIENT_ID}}/access_as_user: Access FiGraph API
# =========================
# aad.manifest.json
# =========================
{
"displayName": "FiGraph-OBO-Proxy",
"signInAudience": "AzureADMyOrg",
"api": {
"requestedAccessTokenVersion": 2,
"oauth2PermissionScopes": [
{
"id": "00000000-0000-0000-0000-000000000001",
"value": "access_as_user",
"type": "User",
"adminConsentDisplayName": "Access FiGraph API as user",
"adminConsentDescription": "Allows the agent to call FiGraph
API on behalf of the user",
"isEnabled": true
}
]
},
"identifierUris": [
"api://YOUR-CLIENT-ID"
],
"requiredResourceAccess": [
{
"resourceAppId": "00000003-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "df021288-bdef-4463-88db-98f22de89214",
"type": "Role"
},
{
"id": "e1fe6dd8-ba31-4d61-89e7-88639da4683d",
"type": "Scope"
}
]
}
]
}
------------------------------
⚙️ Replace these before running
Don’t skip this part—this is where most “it almost works” bugs are born:
-
https://your-api.com → your actual backend URL
-
YOUR-CLIENT-ID → will be auto-filled after aadApp/create, but make sure
it matches
-
(Optional) generate a real GUID for the scope instead of the placeholder
------------------------------
🧪 What happens after you run this
The agent will now:
1.
Get SSO token from Microsoft Entra ID
2.
Send it to FiGraph OBO Proxy
3.
Your backend performs OBO
4.
Calls Microsoft Graph
5.
Returns real data (finally)
@copilot
@QueenFi703
On Thu, Apr 23, 2026 at 3:55 AM Copilot ***@***.***> wrote:
Thanks for asking me to work on this. I will get started on it and keep
this PR's description up to date as I form a plan and make progress.
------------------------------
*This section details on the original issue you should resolve*
<issue_title>SSO + OBO Flow for Declarative Agents Calling Microsoft
Graph</issue_title>
<issue_description>*Is your feature request related to a problem? Please
describe.*
When building a Declarative Agent that calls Microsoft Graph (
/admin/serviceAnnouncement/messages), we could not get SSO working via identityProvider:
MicrosoftEntra on the oauth/register step. The OBO (On-Behalf-Of) token
exchange silently fails — Entra ID sign-in logs show the initial SSO token
is issued successfully (scoped to the agent's own API), but the platform
never performs the OBO exchange to acquire a Microsoft Graph access token.
There is no error surfaced to the developer; the agent simply fails to
retrieve data. Additionally, Entra ID sign-in logs recorded error *50011*
(redirect URI mismatch), indicating the platform sends a redirect URI
during the SSO flow that doesn't match what's configured on the Entra ID
app registration — and the developer has no visibility into or control over
what redirect URI the platform constructs.
*Describe the solution you'd like*
1. *Fix the OBO token exchange* — When identityProvider: MicrosoftEntra
is set and the SSO token is successfully obtained, the platform should
execute the OBO exchange to acquire a downstream API token (e.g., Microsoft
Graph) and surface a clear error if it fails.
2. *Surface diagnostic information* — Provide logging or error output
when the SSO+OBO flow fails, rather than failing silently. Developers
should not need to manually inspect Entra ID sign-in logs to debug
authentication issues.
3. *Resolve the redirect URI mismatch* — The platform should either
automatically configure the correct redirect URIs on the Entra ID app
during oauth/register, or document exactly which redirect URIs must be
present for SSO to work.
4. *Clarify identifierUris ownership* — Document the interaction
between oauth/register (which sets the Application ID URI to
api://auth-{guid}/{clientId}) and aad.manifest.json (which can also
define identifierUris). Setting it in the wrong place silently breaks
the flow.
5. *Provide an end-to-end SSO+OBO sample* — Publish a Declarative
Agent sample that uses SSO to call Microsoft Graph as a downstream API,
covering the full aadApp/create → aadApp/update → oauth/register
lifecycle.
*Describe alternatives you've considered*
1.
*Implementing the OBO token exchange in custom code* — In a
traditional Bot Framework or Azure Function–backed agent, we could
intercept the SSO token and call the Entra ID /oauth2/v2.0/token
endpoint with grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer
to exchange it for a Microsoft Graph token ourselves. However, *Declarative
Agents have no custom backend* — they are purely manifest-driven
configurations where the platform owns the entire auth and API call
pipeline. There is no code entry point where a developer can insert an OBO
exchange. This is why we need the platform to handle the OBO leg natively
when identityProvider: MicrosoftEntra is set.
2.
*Standard OAuth2 authorization code flow (current workaround)* — We
replaced SSO+OBO with OAuth2 auth code flow using PKCE + client secret
(confidential client). This requires a one-time interactive consent prompt
instead of silent SSO, but actually works. Specifically:
- Removed identityProvider: MicrosoftEntra from oauth/register
- Added clientId, clientSecret, and isPKCEEnabled: true to
oauth/register
- Added aadApp/create and aadApp/update steps to the provision
lifecycle in m365agents.yml
- Added explicit scopes (
https://graph.microsoft.com/ServiceMessage.Read.All) to the OpenAPI
spec's operation-level security
With a confidential client, refresh tokens last ~90 days, so users
only re-authenticate after prolonged inactivity. The UX trade-off is
acceptable but SSO would be the ideal experience.
*Additional context*
- *Error evidence*: Entra ID sign-in log entry with error code 50011
is captured in our repo at dev/signin-50011.json — the failure reason
states the redirect URI in the request does not match the redirect URIs
configured for the application.
- *Sign-in log observation*: Logs showed successful AAD Graph SSO
completions but zero Microsoft Graph token requests, confirming the OBO leg
never fired.
- *Entra ID app config*: The app registration included all required
configuration — access_as_user scope, pre-authorized Teams/Office
client app IDs, correct redirect URIs, idtyp optional claim, and
requiredResourceAccess for User.Read + ServiceMessage.Read.All.
- *Architecture constraint*: Declarative Agents are entirely
manifest-driven with no custom backend. The platform is the only component
that can perform the OBO exchange — there is no developer code path to work
around this.
- *Toolkit versions*: M365 Agents Toolkit, m365agents.yml schema
v1.8.</issue_description>
Comments on the Issue (you are @copilot
<https://gh.io/copilot-coding-agent-docs> in this section)
------------------------------
You can view, comment on, or merge this pull request online at:
#15786
<#15786?email_source=notifications&email_token=BJUP7FQ4LYOOJYQTXHOGCBT4XHK65A5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF4ZTKNZSGA4TGMRRGCTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVVYHEX3POBSW4X3DNRUWG2Y>
Commit Summary
- cbcde02
<cbcde02?email_source=notifications&email_token=BJUP7FQI4ID47DLGNMHNHET4XHK65A5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF4ZTKNZSGA4TGMRRGCTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUV5YHEX3DN5WW22LUL5RWY2LDNM>
Initial plan
File Changes
(0 files
<https://github.com/OfficeDev/microsoft-365-agents-toolkit/pull/15786/files?email_source=notifications&email_token=BJUP7FTZ5X3DKUXWD5UH2BL4XHK65A5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF4ZTKNZSGA4TGMRRGCTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVZYHEX3GNFWGK427MNWGSY3L>
)
Patch Links:
-
https://github.com/OfficeDev/microsoft-365-agents-toolkit/pull/15786.patch
<#15786.patch?email_source=notifications&email_token=BJUP7FXXDSWYFTQVQATSM4L4XHK65A5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF4ZTKNZSGA4TGMRRGCTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVZYHEX3QMF2GG2C7MNWGSY3L>
-
https://github.com/OfficeDev/microsoft-365-agents-toolkit/pull/15786.diff
<#15786.diff?email_source=notifications&email_token=BJUP7FXMU2NWAERAW3TQYIL4XHK65A5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF4ZTKNZSGA4TGMRRGCTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVVYHEX3ENFTGMX3DNRUWG2Y>
—
Reply to this email directly, view it on GitHub
<#15786?email_source=notifications&email_token=BJUP7FRXZVCU2JKEAEILVND4XHK65A5CNFSNUABEM5UWIORPF5TWS5BNNB2WEL2QOVWGYUTFOF2WK43UF4ZTKNZSGA4TGMRRGCTHEZLBONXW5KTTOVRHGY3SNFRGKZFFMV3GK3TUVRTG633UMVZF6Y3MNFRWW>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/BJUP7FUC3W55TXGHNM47QTD4XHK65AVCNFSM6AAAAACYDROL62VHI2DSMVQWIX3LMV43ASLTON2WKOZUGMYTINZVGEZTAOI>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
When
identityProvider: MicrosoftEntrais used inoauth/register, the OBO token exchange silently fails due to incorrect AAD app configuration generated by the toolkit templates. Error 50011 (redirect URI mismatch) also fires during SSO because only one of two required redirect URIs was configured.Root causes fixed
identifierUrisconflict — Templates had bothapi://${{OPENAPI_SERVER_DOMAIN}}/${{AAD_APP_CLIENT_ID}}and${{AADAUTHCODE_APPLICATION_ID_URI}}as identifier URIs for the MicrosoftEntra case. Azure AD can issue SSO tokens with the wrong URI as audience, silently breaking the downstream OBO exchange. Fixed to only emit${{AADAUTHCODE_APPLICATION_ID_URI}}(the value set byoauth/register).Missing redirect URI (error 50011) — Only
oAuthConsentRedirectwas registered; the platform also sendsoAuthRedirectduring SSO. Both are now configured for MicrosoftEntra.Scope URI mismatch — OpenAPI spec scopes referenced
api://${{OPENAPI_SERVER_DOMAIN}}/${{AAD_APP_CLIENT_ID}}/repairs_read, inconsistent with the now-single identifier URI. Updated to${{AADAUTHCODE_APPLICATION_ID_URI}}/repairs_read.Silent failures —
oauth/registeronly showed a terse UI popup with no log output. Now emits a structured warning to the log provider and a second info-level OBO diagnostic log.Changes
aad.manifest.json.tpl(ts, js, csharp variants)identifierUris: removedapi://domain/clientId, kept only${{AADAUTHCODE_APPLICATION_ID_URI}}web.redirectUris: addedoAuthRedirectalongsideoAuthConsentRedirectfor MicrosoftEntrarepair.yml.tpl(ts, js, csharp variants) — MicrosoftEntra scope changed fromapi://${{OPENAPI_SERVER_DOMAIN}}/${{AAD_APP_CLIENT_ID}}/repairs_readto${{AADAUTHCODE_APPLICATION_ID_URI}}/repairs_readconstants.ts— AddedmicrosoftEntraOboInfolog key andadditionalRedirectUriconstant (oAuthRedirectURL)create.ts— Warning message now logged tologProviderin addition to the UI popup; new info log emitted with OBO checklist (single identifierUri,access_as_userscope, pre-authorized clients,idtypoptional claim, sign-in log error codes)package.nls.json—microsoftEntraWarningupdated to name both required redirect URIs and explicitly warn against adding extra identifier URIs; newmicrosoftEntraOboInfokey addedWarning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
https://storage.googleapis.com/chromium-browser-snapshots/Linux_x64/950341/chrome-linux.zip/usr/local/bin/node node install.js(http block)If you need me to access, download, or install something from one of these locations, you can either: