Skip to content

plugs: Microsoft 365 as the organization's own Entra application, each person signed in with Microsoft - #343

Merged
richard-epsilla merged 7 commits into
mainfrom
plug-microsoft365
Oct 1, 2026
Merged

richard-epsilla merged 7 commits into
mainfrom
plug-microsoft365

Conversation

@github-actions

@github-actions github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

The enterprise plug, revamped after the Caterpillar review (Richard, 2026-09-30): no API keys, Entra SSO.

  • Plane (gateway/plugs_plane.py, byte-identical with hosted 54193461): identity by config.mode. delegated (default) runs every call as the person the task runs for, with the refresh token they gave when they signed in with Microsoft (kept under rt-<member slug> on the record); application uses client credentials. No sites or people lists: Microsoft's own permissions are the boundary, and its refusal is surfaced as it is. Nine read tools including list_sites. A person who never signed in, or whose sign-in Microsoft revoked, is told to sign in on the Plugins page; the agent never borrows another identity.
  • Registry (self-hosted): connecting checks the ids and the secret at Entra; the delegated identity reads Needs auth until a person signs in. POST /v1/plugs/microsoft365/microsoft/start gives Microsoft's sign-in address with a signed state naming the org, workspace, person and return address; POST /v1/plugs/microsoft/complete redeems the code, keeps the refresh token in the secret store under the person's own field and remembers who they are; POST /v1/plugs/microsoft365/microsoft/signout forgets both.
  • Console: the Plugins row offers Sign in with Microsoft, the settings show who is signed in and a sign-out, and the page finishes the return from Microsoft on /plugins?code=&state=. The identity is a choice on the form.
  • Audit: every call's row names the resource it addressed; the session's member is handed to the plane for a delegated identity.
  • Tests: the hosted plane tests verbatim plus the registry's sign-in flow; gateway suite 714 passed. Guide section rewritten.

End to end on hr-test (0.27.0-rc.3 and again 0.27.0-rc.4 of this branch after the hashed sign-in field, our Azure tenant's application and a test person, 2026-09-30): connect through the console's form (checked at Entra, then Needs auth with the sign-in as the next step); Sign in with Microsoft opened Microsoft's pages, the person registered the second factor the tenant's security defaults require and signed in; back on Plugins the row reads Connected and the settings say who is signed in. A Claude Code task with the plug included then called resources (answered with that person's name, address and tenant), find_people (the directory match) and list_files on its own OneDrive, which Microsoft refused with its own sentence ("Tenant does not have a SPO license"), reported verbatim and not worked around.

Not in this slice (next steps from the meeting): pass-through of an Entra token sent on the task request, and fronting Microsoft's remote MCP servers with the person's token.

🤖 Generated with Claude Code

@vercel

vercel Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
unified-harness-protocol Ready Ready Preview Oct 1, 2026 4:12am UTC

Request Review

…h person signed in with Microsoft

The plane is the hosted tree's, byte for byte (54193461): identity by config.mode, delegated by
default (the calling person's refresh token, kept under rt-<member slug> on the record, redeemed
for a Graph token), or the application (client credentials); no sites or people lists, Microsoft's
own permissions are the boundary and its refusal is surfaced as it is; list_sites; a person who
never signed in is told to sign in on the Plugins page. The local registry checks the ids and the
secret at Entra when the plug is connected, runs the sign-in (start with a signed state naming the
org, workspace, person and return address; complete redeems the code, keeps the refresh token in
the secret store and remembers who signed in; sign-out forgets both), and the console's Plugins
page offers Sign in with Microsoft, shows who is signed in, and finishes the return. Guide text:
the identity, list_sites, never another identity.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@richard-epsilla richard-epsilla changed the title plugs: Microsoft 365, the workspace's own Entra application on the sites and people it approved plugs: Microsoft 365 as the organization's own Entra application, each person signed in with Microsoft Sep 30, 2026
…er id (hosted af17a309, plane byte for byte)

The first hosted sign-in wrote an 84-character vault key name and the vault refused it, so the
field a person's refresh token is kept under is now rt- plus sixteen hex characters of the
member id's hash, the same derivation on both registries: a record written by either reads on
either gateway. The local registry already derives the field from the plane.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…o nobody on the record

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

@richard-epsilla richard-epsilla left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Up to date with main; the four required checks pass.

@richard-epsilla
richard-epsilla merged commit 3116772 into main Oct 1, 2026
15 of 16 checks passed
richard-epsilla added a commit to ZixiaoL/harnessrouter that referenced this pull request Oct 3, 2026
…h person signed in with Microsoft (HarnessRouter#343)

* plugs: Microsoft 365 as the organization's own Entra application, each person signed in with Microsoft

The plane is the hosted tree's, byte for byte (54193461): identity by config.mode, delegated by
default (the calling person's refresh token, kept under rt-<member slug> on the record, redeemed
for a Graph token), or the application (client credentials); no sites or people lists, Microsoft's
own permissions are the boundary and its refusal is surfaced as it is; list_sites; a person who
never signed in is told to sign in on the Plugins page. The local registry checks the ids and the
secret at Entra when the plug is connected, runs the sign-in (start with a signed state naming the
org, workspace, person and return address; complete redeems the code, keeps the refresh token in
the secret store and remembers who signed in; sign-out forgets both), and the console's Plugins
page offers Sign in with Microsoft, shows who is signed in, and finishes the return. Guide text:
the identity, list_sites, never another identity.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* ci: start checks

* plugs: a person's Microsoft sign-in field is a short hash of the member id (hosted af17a309, plane byte for byte)

The first hosted sign-in wrote an 84-character vault key name and the vault refused it, so the
field a person's refresh token is kept under is now rt- plus sixteen hex characters of the
member id's hash, the same derivation on both registries: a record written by either reads on
either gateway. The local registry already derives the field from the plane.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* plugs: a Microsoft sign-out also drops a sign-in field that belongs to nobody on the record

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: richard-epsilla <richard@epsilla.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>

This branch was successfully deployed

1 active deployment
Preview — a72efe3c Deployed Oct 1, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant