Repository navigation
[AI-1543] Check the account on a session connection's first consent - #1110
Merged
Merged
Conversation
The app's backend says which email its user signs in with in X-Stream-User-Email, read from a server-side caller only and kept per user. A manifest that sets owner_email refuses a user-owned connection's first consent, storing nothing, unless the id_token's email is that one. nessy.yaml opts in (revision 2). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t-consent-account
…t-consent-account
…an end user Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…heck test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.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.
AI-1543: check the account on a session connection's first consent
A consent link works in any browser (
authorizations.go, launch page + cookie). Staff member A can send it to B, and B's Nessy grant would land on A's connection, so A's agent would act as B. The account check ran only once a connection already had an account.Decision (Q6 amended, 2026-10-21): the app's backend says the user's email, with the same trust as
X-Stream-User-Id. The router keeps the latest one per user and compares it with theid_tokenemail on the first consent.X-Stream-User-Email, read from a server-side caller only (APIKey server branch; ProxyKindServer)internal/auth/auth.gousers.email, migration20261105140000)internal/api/server.gorecordEmail,internal/store/sessions.goSetUserEmail/UserEmailowner_email: truemanifest opt-in; needs a requiredemailcapture from theid_tokeninternal/connectors/core/manifest.gointernal/api/authorizations.gocompleteConsent,ownerEmailRefusalsub(identity),email, optionalemail_verified; revision 2providers/nessy.yamlinternal/api/connection_proxy.goOpenIDpersonality (Nessy's id_token shape)fakeproviderFirst production caller: the consent callback
/v1/agents/connectors/oauth/callback(finishConnectorConsent→completeConsent). Consents begun from a session's tool call (ConnectorConsents) finish at the same callback and are checked against the same stored email (TestAChatConsentIsCheckedAgainstTheSameEmail).No other connector changes: only a manifest with
owner_emailis checked (TestAConnectorThatDoesNotCheckTheEmailConnectsAnyAccount, whose expectedconnectedwas probed on basea103c19ab). App-owned connections and reconnects of a connection that already has an account are not email-checked (a reconnect keeps the existing account check).Docs:
audit.goactor_nameno longer says the router keeps no email; README auth section, providers AGENTS.md, security-scheme description, sdk skill note for the other SDKs. Clients regenerated: Go, Python, JS (Kotlin/Swift--checkpass, nothing client-accessible changed).What Athena must change (not in this PR): send
X-Stream-User-Email: <employee email>besideX-Stream-User-IdinemployeeAgentAuth.headers(athena-aiserver/internal/api/agent_transport.go:30-38), taking the email from its employee record (access.Membership.Email,server/internal/access/access.go:85-88), on the server-side calls made before a consent (session create, connection create, start consent).Tests
internal/auth: an end user's device never sets the email (user token, user token + server header, server token without the header, anonymous); a declared backend does.TestAuthorizationsSuite: owner's own consent connects; another account is refused and stores nothing (no credentials, no account, no audit row); no email said is refused; chat consent path refused; reconnect checked by account, not email; app-owned not checked; control; only the backend's header is kept, latest wins.ownerEmailRefusalunit test;owner_emailmanifest validation; Nessy consent at the fake readssub/email.🤖 Generated with Claude Code