Add sso-setup-typescript plugin (Entra SSO for ui-widget agents) + expand authentication.md#156
Conversation
…pand authentication.md New plugin sso-setup-typescript: setup-sso base skill (+4 references) and setup-sso-ui-widget, which adds Entra SSO to ui-widget-developer agents (MCP server + mcpPlugin.json), reusing the existing devtunnel; SSO only, no OBO. Includes a new sso-explained.md reference (token flow, client-id-GUID audience, 401-vs-403 consent loop). Audience fix: the auth.ts guard accepts [clientId, api://clientId, appIdUri] because a real M365 Copilot SSO token's aud is the bare client-id GUID. Public/external-only: no hardcoded tenant IDs or internal portals; standard registration path with generic admin-consent guidance. Conversation starters added conditionally. Update declarative-agent-developer/references/authentication.md with the full Entra SSO section.
… temp file - Pre-authorized apps: remove the 'add Teams/Office/Outlook client IDs later' note; a DA only needs M365 Copilot (ab3be6b7). Keeps the preAuth list to a single entry. - NO SCRATCH FILES ban: add the same permitted-exception carve-out as internal for the short-lived az rest --body @file temp file.
88acc18 to
53efe18
Compare
Thorough review —
|
…5-agents-toolkit Addresses reviewer direction (Eric/Sebastien): don't ship a separate plugin (avoids a discovery issue), and drop the base setup-sso skill (its 'validation illusion' - it never injected/verified the guard). - Move setup-sso-ui-widget into plugins/microsoft-365-agents-toolkit/skills/ (auto-discovered via the plugin's skills:./skills/). - Fold the former base setup-sso references (entra-app-registration, entra-app-update, dev-tunnel, admin-consent) into the skill so it is fully self-contained. - Delete the standalone plugins/sso-setup-typescript plugin (plugin.json, README, base setup-sso skill). - Stays on PowerShell (de-PowerShell rewrite parked per Sebastien: the model adapts to PS).
Addresses Sebastien's security review of the injected guard: - microsoft#1 Enforce scp contains access_as_user and reject app-only (idtyp=app) tokens, so audience acceptance is no longer the only gate and a real signed-in user is always present. - microsoft#2 Single-tenant only: pin the issuer to the tenant's v2 endpoint + defense-in-depth tid match; documented single-tenant-only. - microsoft#6 Drop the v1 sts.windows.net issuer (app issues v2 tokens). - microsoft#4 Return a generic 401 (Authentication required) to the caller; log the detailed reason server-side only. - microsoft#8 Gate the per-request [auth] identity log behind SSO_DEBUG=1 so it never logs identifiers in prod (test steps set it). - Rip the guard source out of SKILL.md into references/auth.ts (keeps the skill lightweight, per Sebastien); Phase 7a now copies that file in.
- YAML provision:-insert: guard the IndexOf newline -1 case (provision: as the file's last line with no trailing newline) so it no longer inserts at offset 0 and corrupts the yml. - entra-app-registration: force single-tenant (AzureADMyOrg) to match the single-tenant guard, and document that multi-tenant is unsupported (microsoft#2). Drop 2>\ on az ad app create and fail clearly on an empty ClientId instead of confusing downstream errors. - microsoft#7 Least privilege: make Graph User.Read + admin consent OPT-IN (only for OBO/Graph); pure SSO needs neither. Updated Step 5 + the verify expectation + the SKILL Phase 5 summary.
- authentication.md: the 'Invalid redirect URI' troubleshooting row now distinguishes SSO (oAuthConsentRedirect) from third-party OAuth (oAuthRedirect), resolving the contradiction with S1. - authentication.md: document the concrete key names the setup-sso-ui-widget skill uses (MCP_DA_OAUTH_AUTH_ID / MCP_DA_OAUTH_APP_ID_URI) so the doc and automation align. - sso-explained.md: point the audience rule (3.2) and the 401-vs-403 table (6.1) at authentication.md as the canonical source instead of restating them near-verbatim (drift risk), keeping only the skill-specific auth.ts detail.
…toolkit authentication.md pointed at the retired sso-setup-typescript plugin; update it to reference the setup-sso-ui-widget skill in this same plugin and link sso-explained.md relatively.
|
@microsoft-github-policy-service agree company="Microsoft" |
…t resync + Azure/Easy Auth note - Move phase logic from reference .md into real scripts/*.ps1 (13 scripts + _lib), .md files invoke them via pwsh -File $SsoScripts/x.ps1. - Group references into detect-and-inputs / register-app / wire-and-guard / build-verify-cleanup; delete old per-phase .md. - wire-mcpplugin.ps1: copy the widget's own conversation_starters from mcpPlugin.json into declarativeAgent.json when the DA defines none (no synthetic starters); fix @($null).Count==1 guard. - Add scripts/resync-tunnel-url.ps1 + Phase 2 drift check: keep OAuth baseUrl/App ID URI aligned when the dev tunnel URL changes. - SKILL.md: Azure Easy Auth deployment note (Learn links), tunnel-changed recovery in Notes & Error Handling + FINAL SUMMARY caveat. - ui-widget-developer: add optional 'Add SSO' handoff to setup-sso-ui-widget.
… a passive footer)
…w-http) layouts
- Broaden skill description to cover both widget standards (default MCP Apps) so Copilot auto-selects it for create-mcp-app projects, not just ui-widget-developer.
- _lib.ps1: add Get-PluginManifest (filename-agnostic via declarativeAgent.json actions[].file -> mcpPlugin.json OR readiness_plugin.json) + Get-ServerStyle (express vs rawhttp).
- detect-project.ps1: accept either manifest, report layout + server style, persist SSO_SERVER_STYLE.
- wire-mcpplugin.ps1: patch the resolved manifest (not hardcoded mcpPlugin.json).
- inject-guard.ps1: jose + dotenv (Express); place auth.ts next to the server entry (src/ for raw-http, root for Express main.ts).
- wire-and-guard.md: Phase 7b split into Variant A (raw-http) + Variant B (Express app.all('/mcp')), both reuse auth.ts; 7c CORS for both.
Validated end-to-end on an Express/MCP Apps project (readiness_plugin.json): guard enforces 401 and accepts valid Copilot SSO tokens.
…lugin integration
After adding an MCP server as a plugin to a DA, offer to run setup-sso-ui-widget. Completes the create-mcp-app -> add MCP plugin -> SSO path (no separate wrap step). Validated end-to-end: DA-dev emits {name}-plugin.json, which the SSO skill resolves filename-agnostically and patches to OAuthPluginVault.
…asy Auth config) Per Eric's deployment feedback: codify the field-by-field Easy Auth blade config (App Service -> Authentication -> Microsoft Entra) so the model configures it right first time instead of iterating. Includes the two gotchas: audience must be the bare client-id (else 401), and Allowed client applications must include the M365 Copilot host client id ab3be6b7 (else 403). Maps placeholders to this skill's CLIENT_ID/TENANT_ID + the Copilot host id from Phase 5. Linked from the Azure notes in wire-and-guard.md and SKILL.md FINAL SUMMARY.
…d so it always prints The model was paraphrasing the FINAL SUMMARY deployment note and dropping the easy-auth.md reference. Rewrite it as a reproduce-verbatim block with concrete values (ClientId, TenantId, M365 Copilot host id ab3be6b7) + the two gotchas inline + easy-auth.md cited by name, so the Easy Auth guidance surfaces reliably in every run.
Summary
Adds a
setup-sso-ui-widgetskill to themicrosoft-365-agents-toolkitplugin: one-command Microsoft Entra SSO (single sign-on, no OBO) for a Microsoft 365 Copilot declarative agent whose tools are served by an MCP server. It supports both widget standards — MCP Apps (Express) and OAI Apps (raw-http) — and defaults to MCP Apps. Also expandsdeclarative-agent-developer/references/authentication.mdand adds an SSO hand-off toui-widget-developer.What's included
New skill —
setup-sso-ui-widget/scripts/*.ps1(14) — the phases as real, testable PowerShell (detect → register Entra app → ATK OAuth → wire manifest → inject guard → write env → build/sideload → verify 401 → cleanup), plusresync-tunnel-url.ps1and_lib.ps1. The.mdfiles invoke the scripts (deterministic — works well with smaller models, not just Opus).references/—wire-and-guard.md,detect-and-inputs.md,register-app.md,build-verify-cleanup.md,auth.ts(hardened JWKS guard),sso-explained.md(token-flow deep dive).Dual-layout support
readiness_plugin.json+ Expressmain.ts) vs OAI Apps (mcpPlugin.json+ raw-http). Defaults to MCP Apps when ambiguous.runtimes[]auth →OAuthPluginVault(filename-agnostic).auth.tsguard, wired per layout: an Express middleware for MCP Apps, or a raw-http handler edit for OAI Apps (noexpress-jwt, no server rewrite).Updated
ui-widget-developer/SKILL.md— required "Add SSO" hand-off at completion.declarative-agent-developer/references/authentication.md— expanded from OAuth-only to a full auth guide (Entra SSO S1–S6, auth-pattern chooser, 401-vs-403 consent-UX guidance).Security
Single-tenant JWKS bearer-token guard: validates signature /
aud/iss/expviajose, and additionally enforcesscp = access_as_user, tenant match, and rejects app-only tokens. Accepts everyaudform Entra emits (bare client-id GUID +api://…) to avoid the endless consent loop, while still rejecting tokens minted for a different app. Includes an Azure Easy Auth deployment note (the custom guard is for local dev).Tunnel resilience
Reuses the existing named devtunnel (never creates a second). If the tunnel URL later changes,
resync-tunnel-url.ps1(+ a Phase-2 drift check) re-aligns the OAuth base URL / App ID URI so auth doesn't break.Tenant handling
No hardcoded tenant IDs or internal portals. Defaults to the standard single-tenant registration; managed-enterprise steps (
--service-management-reference, co-owners, admin-consent portal) trigger reactively only if app creation requires them.Testing
Validated on a public Microsoft Entra tenant across both layouts:
src/+401enforcement.401+ valid Copilot SSO tokens accepted ([auth] Valid SSO token accepted).Notes
create-mcp-appemits a standalone MCP server with no M365 agent wrapping; this skill assumes the project is already wrapped as a declarative agent. A clean "create-mcp-app → M365 agent" wrap step is a follow-up.