Skip to content

Link personal Slack accounts to existing web identities - #1442

Open
ReganBell wants to merge 11 commits into
mainfrom
codex/connect-slack-identity
Open

ReganBell wants to merge 11 commits into
mainfrom
codex/connect-slack-identity

Conversation

@ReganBell

@ReganBell ReganBell commented Sep 19, 2026

Copy link
Copy Markdown
Contributor

People who start on the web and later message QM in Slack can end up with separate identities, losing access to the connectors they already authorized. Add a dedicated personal Slack OAuth flow that verifies workspace and user identity, preserves the web account as canonical, and refuses conflicting accounts with existing credentials or connections.

Onboarding now presents Add to Slack first, then a compact installation checkmark and the personal linking card. The agent can recall the card with ::link-slack-account{}. Trusted Bookface entry failures no longer offer an alternate email login. Includes principal-link concurrency, deactivation, and stale portal identity fixes.

This includes the principal-link implementation from the existing principal-links proposal, rebased on main.

Validation: all public CI checks passed at 928afc6c; fleet tests 828 passed, 3 skipped; fleet config check passed. Independent identity, portal, full infrastructure, and staged application-plan reviews found no blockers. Deployed the exact clean source to Styleup with digest-pinned core, web-ui, and portal images. Infrastructure is unchanged; the existing deployment instruction bundle was preserved.

Live browser QA verified the installed-bot checkmark and personal linking card, working app catalog, a real model response rendering ::link-slack-account{}, and the personal button reaching Composio's Slack user OAuth. The managed bot re-install button also reaches Slack consent. No installation/account-link status is mocked. OAuth completion remains unverified: this browser is signed into YC, which restricts Composio; completing the test requires a Development YC login. No Slack consent or install request was submitted.

Hosted test: https://styleup.qm.ycombinator.com/s/cf810776-de84-4a1f-a64c-038e959edaf1

A founder who reaches qm through Slack, an email magic link, and a trusted
OIDC provider gets three principal ids and is treated as three people. A
secret drop minted from Slack belonged to the email principal, and the same
person signed in through OIDC was told the link was for someone else.

Add principal links: an org admin records that a sign-in id belongs to a
canonical principal, with evidence. personKey and samePerson fold a linked
sign-in to its canonical id, so ownership recorded under either id belongs to
the person: keychain credentials, admin grants, approvals, secret drops,
sessions. New writes use the canonical id: the identity service classifies a
linked sign-in as its canonical principal, the portal resolves the session
subject before proxying, core canonicalizes the verified portal actor, and
the keychain saves under the canonical owner. Links live in the
principal_links durable map and refresh with the identity service.

The directory member stays canonical; the admin API refuses a link whose
linked side is a directory member, refuses chains, and requires evidence.
Links are portal-only like grants and impersonation. Deleting a link restores
two separate principals.
The directory-member guard now also refuses a Slack id, since a roster row
carries both ids and personKeys would otherwise merge two people. A sign-in
that holds an org admin grant can only be linked to a canonical principal
that is already an admin, so a link never grants admin silently.

Deactivations and external members are stored under the raw folded id and
folded to the person only in memory, so a deactivation recorded before a link
stays reversible and an external member can still be removed afterwards.
Directory-sync protection is evaluated at check time for the same reason.

Credential ids derive from the canonical owner, so the same person saving the
same service from either sign-in rotates one record. The canonical lookup
forces an identity refresh. The portal refuses to proxy when core cannot
resolve the session subject instead of acting as the raw subject, and the
impersonation self-check compares canonically.
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