Repository navigation
Fix Microsoft 365 sign-in session race and auto-create the workflow key - #1716
Merged
Paul Lizer (paullizer) merged 2 commits intoOct 8, 2026
Conversation
…ate the workflow key automatically Flask-Session rewrote the whole session at the end of every request, so a slow V2 bootstrap refresh that overlapped a Microsoft 365 connect wrote back a stale copy, erased the pending sign-in, and /getAToken answered m365_auth_state_invalid. - Install merging Redis and filesystem session interfaces that save only the keys a request changed onto the latest stored session, refresh only the TTL when nothing changed, and never recreate a session deleted mid-request. - Create the deployment-wide workflow encryption key in Key Vault on first connect and on admin settings saves, report readiness, and route workflow sign-in through /getAToken. - Show sign-in results on a page that reports back to the popup's opener instead of raw JSON. - Derive the chat connection's sources from the session token cache, keep V2 links in V2, and skip V2 focus refreshes while a recent one exists. - Bump to 0.261.302 with tests, fix documentation and release notes. Fixes microsoft#1714 Refs microsoft#1604 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
… assert result page statuses Code scanning reported the workflow key's Key Vault URL as full server-side request forgery: the vault name, which an admin settings save can supply, became the request's hostname. The readiness check already fullmatched the name, but in another function, so the request site did not show it. _load_workflow_key now fullmatches the exact stripped name it puts in the URL, so every request stays on a vault in the configured Key Vault domain. A new test bypasses readiness and confirms that invalid names never reach SecretClient. The result page tests now assert the HTTP status they were discarding. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer)
merged commit Oct 8, 2026
81e78a3
into
microsoft:paullizer-react-v2-ui
11 checks passed
Paul Lizer (paullizer)
added a commit
to paullizer/simplechat
that referenced
this pull request
Oct 8, 2026
Resolve the version and release-notes conflicts with microsoft#1716: keep VERSION 0.261.303 and keep both release-note sections, v0.261.303 above v0.261.302. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
14 of 24 tasks
Paul Lizer (paullizer)
added a commit
to paullizer/simplechat
that referenced
this pull request
Oct 8, 2026
… flow branch Brings in microsoft#1716 (Microsoft 365 sign-in session race fix, automatic workflow encryption key, Microsoft 365 links that stay in V2). Conflict and semantic resolutions: - release_notes.md: both branches added entries under v0.261.302; kept both sets. The next commit moves this branch's entries to their own version. - microsoft#1716 moved M365_APPROVALS_HREF from m365Connect.ts to m365Links.ts as an in-app router path (/approvals/m365) rendered with Link. The inline approval card now imports it from there and renders a Link, and its Settings link uses the new section deep link to the Microsoft 365 sharing card, where Extended analysis is set (M365_SHARING_PREFERENCES_HREF). - The m365Links guardrail test pins every exported link the XSS checker trusts by name; it now pins the new sharing-preferences path. - The inline approval UI test expects the new in-app link paths. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Paul Lizer (paullizer)
added a commit
to paullizer/simplechat
that referenced
this pull request
Oct 8, 2026
microsoft#1716 shipped as 0.261.302, the version this branch used, and the open Microsoft 365 citations PR (microsoft#1718) holds 0.261.303. Move this branch to 0.261.304: config.py, its own release-notes section above v0.261.302, and the version headers and "Since" notes in its code, tests and docs. The fix doc also lists the sharing-preferences link and guardrail pin added when the base was merged. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
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.
Summary
Microsoft 365 connections broke on a 3-instance deployment even though chat could read mail and SharePoint. Reconnecting for chat failed with
m365_auth_state_invalid, and connecting for workflows asked for a Key Vault secret nobody had created. The settings card also reported no sources, and V2 links opened classic pages. Application Insights showed why sign-in failed: Flask-Session rewrites the whole session at the end of every request. A V2 bootstrap refresh fires on window focus and takes about 5 s. When it overlapped the connect call, it wrote back a stale copy that erased the pending sign-in before/getATokenran.WATCH/MULTI/EXEC. A request that changed nothing only refreshes the TTL, and a session deleted mid-request is never recreated. This fixes the sign-in failure and protects every other session write. V2 also skips a focus refresh while one is running or one started in the last 15 s.M365_WORKFLOW_TOKEN_KEY_SECRET_NAMEstill overrides the name. Workflow sign-in now returns through/getAToken, which is already registered. Connect is disabled with an explanation until Key Vault secret storage and a vault name are configured.Review notes:
configure_sessionsruns inbefore_request. That session has no snapshot and is written whole, as before.m365_key_provision_forbidden, and an admin save that changes the Key Vault settings shows a warning. Decryption pins the stored key version and never creates a key, so two racing first connects only leave an unused extra version.scope, which MSAL stores as the access token target. This hasn't been checked against a live tenant yet.GET /api/v2/bootstraplatency, and the delegated Graph permissions inInitialize-EntraApplication.ps1(Deployers don't configure Microsoft 365 workflow connections (Key Vault key, callback redirect URI, delegated Graph permissions) #1604).Linked issue
Fixes #1714
Refs #1604 (this covers the workflow key and callback; the deployer's delegated Graph permissions remain open)
Release Notes & Latest Features
Is this visible to end users?
Is this admin-facing (Admin Settings, governance, deployment, config)?
Should this become a Latest Feature card?
Screenshot needed for the card?
Version bump
application/single_app/config.pyVERSIONthird segment bumped, or not needed because this is docs-onlydeployers/version.txtbumped, or not needed becausedeployers/was not changed0.261.301to0.261.302. Nothing underdeployers/changed.Testing / validation
Run on the pushed commit (
a4d5bcdbc) on Windows with Python 3.12 andPYTHONIOENCODING=utf-8. Every failure listed also happens on the base commitfa3422dee, checked in a clean worktree.python -m pytest functional_tests\test_session_store_merge.py functional_tests\test_m365_connections.py functional_tests\test_m365_routes.py functional_tests\test_v2_user_settings_memory_m365.py functional_tests\test_v2_workflow_run_tracking_xss_guardrail.py functional_tests\test_ai_connection_embedding_defaults_api.py functional_tests\test_content_screening_admin_settings_fix.py -q -p no:cacheprovider -W ignore: 149 passed, 153 subtests passed, 10 failed. Pre-existing: 9 intest_ai_connection_embedding_defaults_api.py(NameError: KeyVaultSecretStorageErrorin its test harness) andtest_m365_routes.py::M365RouteTests::test_real_notification_helper_only_targets_subject_and_deduplicates(localImportError: cannot import name 'assert_group_role').python -m pytest functional_tests\route_tests\test_route_blueprint_policy_inventory.py functional_tests\route_tests\test_route_unauthenticated_policy_contract.py functional_tests\route_tests\test_route_policy_test_coverage.py -q -p no:cacheprovider -W ignore: 26 passed.python .\functional_tests\test_docs_app_surface_coverage.py: 7/7 checks passed.python .\functional_tests\test_docs_site_quality.py: 6/6 checks passed.npm --prefix application\v2_ui run typecheck: passed.node functional_tests\<name>.mjsfor all 84.mjssuites: 80 passed, 4 failed. Pre-existing:test_v2_admin_nested_setting_reads,test_v2_workspace_action_authoring_logic,test_v2_workspace_action_connectors_logic,test_v2_workspace_agent_picker_rendering.npm --prefix application\v2_ui run build -- --outDir ..\..\ui_tests\artifacts\orchestration-plan-editor, thenpython -m pytest ui_tests\test_m365_connection_result_page.py ui_tests\test_v2_settings_m365_connections.py ui_tests\test_v2_orchestration_m365_recovery.py ui_tests\test_v2_orchestration_workflow_proposal_card.py ui_tests\test_m365_lifecycle_and_approvals.py ui_tests\test_m365_pending_action_cards.py -q -p no:cacheprovider -W ignore: 220 passed, 1 error. Pre-existing: setup oftest_real_typed_tools_and_flask_stream_produce_usable_browser_cardsfails on a local pyOpenSSLGEN_EMAILmismatch.python scripts\check_xss_sinks.py --base-sha fa3422dee --head-sha HEAD $(git diff --name-only fa3422dee..HEAD -- '*.js' '*.html' '*.ts' '*.tsx' '*.py'): passed for 38 files.python -m pyflakes $(git diff --name-only fa3422dee..HEAD -- '*.py'): no new findings compared withfa3422dee, apart from more uses of names these files already take from star imports (flash,request) and the shared Playwright fixture import already marked# noqa: F401.fa3422dee.Documentation
Release notes are under v0.261.302. New fix doc:
docs/explanation/fixes/M365_CONNECTION_SESSION_RACE_FIX.md. Also updatedMICROSOFT_365_ACTIONS.md,CHAT_ORCHESTRATION_WORKFLOWS_ROADMAP.md,docs/admin/security.md,docs/reference/logging-tags.md([SESSION_STORE]), and the regenerateddocs/_data/app_surface.yml.Security checklist
@swagger_route(security=get_auth_security())sanitize_settings_for_user()No new application routes; the only new
@app.routes are in the session test's throwaway Flask app.GET /api/m365/connectionsadds a derived readiness object (available,reason,message), not settings. The result page loads the localstatic/js/profile/profile-m365-connection-result.jsand posts only to its same-origin opener. The key value is never logged or sent to the browser.