Skip to content

Capture OAuth signup attribution - #209

Open
Jayko001 wants to merge 2 commits into
mainfrom
hypeship/oauth-attribution-survey
Open

Jayko001 wants to merge 2 commits into
mainfrom
hypeship/oauth-attribution-survey

Conversation

@Jayko001

@Jayko001 Jayko001 commented Sep 22, 2026

Copy link
Copy Markdown

summary

  • require two attribution answers before an org-less OAuth user can create an organization
  • preserve dynamic OAuth client registration metadata and record the observed client ID and redirect origin
  • store the answers and client context on the Clerk user before organization creation
  • keep organization creation blocked when attribution persistence fails

The existing $mcp_initialize event already records $mcp_client_name and $mcp_client_version with the organization group. Together, these fields distinguish discovery, connection trigger, OAuth application, and the first MCP runtime without treating any one signal as authoritative.

The analytics half is kernel/kernel#4269. Merge and deploy both changes before evaluating coverage.

data captured

  • firstDiscoverySource
  • connectorTrigger
  • signupPath
  • oauthClientId
  • oauthClientName (self-reported during dynamic registration)
  • oauthClientUri (self-reported origin)
  • oauthRedirectOrigin (observed authorization request)
  • oauthClientType

tests

  • bunx tsc --noEmit
  • bun test (611 passing)
  • production bun run build with local placeholder configuration

Note

Medium Risk
Touches OAuth registration and Clerk user metadata with redirect-uri validation; Redis metadata loss is non-blocking for registration but affects attribution enrichment.

Overview
Adds OAuth signup attribution for users on /select-org who have no organization: they must answer a short discovery/trigger survey before Create organization appears. Answers and OAuth context are written to Clerk publicMetadata via saveOAuthAttribution; returning users with valid metadata skip the survey.

Dynamic registration now stores client name, optional client_uri, and redirect URIs in Redis (180-day TTL) after Clerk creates the app. Attribution enriches metadata with oauthClientId, registered client name/URI, client type, and an observed redirect origin only when the authorize query redirect_uri matches stored redirects (localhost expansion included); mismatches drop oauthRedirectOrigin so arbitrary callback URLs are not trusted.

Registration failures to save metadata are logged and do not fail the registration response; survey save failures keep org creation blocked until success.

Reviewed by Cursor Bugbot for commit cecbc94. Bugbot is set up for automated code reviews on this repo. Configure here.

@vercel

vercel Bot commented Sep 22, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated
mcp Ready Ready Preview Sep 22, 2026 9:18pm UTC

The select-org query string is browser-controlled, so a mismatched
redirect_uri could pair a real client ID with an unrelated origin.
For dynamically registered clients, drop the redirect origin unless it
matches one of the client's registered redirect URIs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@masnwilliams masnwilliams 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.

The survey and metadata flow are locally clear, but I think the ownership boundary needs correction before merge.

Blocker — cover the canonical signup path. Production MCP protected-resource discovery advertises https://auth.onkernel.com; new registrations authorize through the Go server and its dashboard organization picker. This PR gates src/app/select-org/page.tsx, the retained TypeScript picker for legacy clients. As written, new MCP users can create an org without seeing these questions, so the stated signup coverage will not follow from this change. Please put the survey on the canonical picker too, or show that the targeted new-signup cohort actually reaches this page and narrow the PR scope accordingly.

Follow-up — bind client attribution to the creation attempt. saveOAuthAttribution stores the client details on the user, and the picker skips the action on future visits once survey answers exist. A user can answer via client A, abandon org creation, and later create their first org via client B; provisioning would attribute that org to A. Can the discovery answer remain user-level while the client context is refreshed or tied to the current org-creation flow?

I am not asking to block on the redirect-origin fallback for clients with no registration metadata or on the existing attribution_source property.

This branch was successfully deployed

1 active deployment
Preview cecbc945 Deployed Sep 22, 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.

2 participants