Skip to content

fix(auth): use scoped_teams when scoped_organizations is empty#2490

Closed
raquelmsmith wants to merge 1 commit into
mainfrom
posthog-code/use-scoped-teams
Closed

fix(auth): use scoped_teams when scoped_organizations is empty#2490
raquelmsmith wants to merge 1 commit into
mainfrom
posthog-code/use-scoped-teams

Conversation

@raquelmsmith
Copy link
Copy Markdown
Member

@raquelmsmith raquelmsmith commented Jun 4, 2026

human description

I could not get an agent to run when using local PostHog. After an hour with claude it tells me this is the fix - and now it's working locally.

Summary

  • scoped_organizations is empty when the OAuth grant is project-level — PostHog returns scoped_teams instead. The old code only consulted scoped_organizations, so project-scoped logins ended up with an empty orgProjectsMap, no currentProjectId, and "No projects available" in the switcher (downstream: Missing auth credentials and the agent failing to start a session).
  • Add scoped_teams to the OAuth token Zod schema and, when scoped_organizations is empty, build the org/project map from scoped_teams: fetch each project via /api/projects/<id>/, group by organization, then fetch each org's name. Only the teams the user actually authorized are included.
  • Org-level grants are unchanged — scoped_organizations path still wins when populated.

Test plan

  • Log out, log back in selecting Dev region, grant access to a single project on the PostHog consent screen.
  • Verify the project switcher shows the org and the granted project, and a session starts (no Missing auth credentials in ~/.posthog-code/logs-dev/main.log).
  • Re-test with an org-level grant (e.g. against US/EU) to confirm the existing path still works.

🤖 Generated with Claude Code

…zations is empty

PostHog returns `scoped_teams` instead of `scoped_organizations` when the
OAuth grant is project-level. Before this, project-level tokens produced
an empty orgProjectsMap, leaving currentProjectId null and surfacing
"no projects available" in the switcher.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@raquelmsmith raquelmsmith requested a review from a team June 4, 2026 22:00
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jun 4, 2026

Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 2
apps/code/src/main/services/auth/service.ts:635-640
**Project-scoped token may always yield "(unknown)" org name**

`fetchOrgWithProjects` calls `/api/organizations/${orgId}/` using the same access token. A project-scoped OAuth grant is unlikely to carry permission to read the org endpoint, so `res.ok` will be `false`, the function returns `null`, and every project-scoped login will display `"(unknown)"` as the org name in the switcher. The PR test plan specifically checks that the org name is visible — worth confirming the token does have org-read access, or falling back to the project's own `organization` ID as the display label when the org fetch fails.

### Issue 2 of 2
apps/code/src/main/services/auth/service.ts:632-643
**Superfluous full-org fetch: only `orgName` is consumed**

`fetchOrgWithProjects` issues a network request to `/api/organizations/${orgId}/` and parses the entire `teams` array — all of which is discarded, since `projects` in the returned tuple comes from `projectsByOrg` (the scoped team metas), not from the org call. Consider extracting a thin `fetchOrgName` helper that skips the `teams` mapping, or at least skip the call entirely when the org ID can be used as a display label. This follows simplicity rule 4 (no superfluous parts) and avoids the unnecessary allocation on each login.

Reviews (1): Last reviewed commit: "fix(auth): build org/project map from sc..." | Re-trigger Greptile

Comment on lines +635 to +640
const org = await this.fetchOrgWithProjects(
accessToken,
cloudRegion,
orgId,
);
return [orgId, { orgName: org?.orgName ?? "(unknown)", projects }];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Project-scoped token may always yield "(unknown)" org name

fetchOrgWithProjects calls /api/organizations/${orgId}/ using the same access token. A project-scoped OAuth grant is unlikely to carry permission to read the org endpoint, so res.ok will be false, the function returns null, and every project-scoped login will display "(unknown)" as the org name in the switcher. The PR test plan specifically checks that the org name is visible — worth confirming the token does have org-read access, or falling back to the project's own organization ID as the display label when the org fetch fails.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/main/services/auth/service.ts
Line: 635-640

Comment:
**Project-scoped token may always yield "(unknown)" org name**

`fetchOrgWithProjects` calls `/api/organizations/${orgId}/` using the same access token. A project-scoped OAuth grant is unlikely to carry permission to read the org endpoint, so `res.ok` will be `false`, the function returns `null`, and every project-scoped login will display `"(unknown)"` as the org name in the switcher. The PR test plan specifically checks that the org name is visible — worth confirming the token does have org-read access, or falling back to the project's own `organization` ID as the display label when the org fetch fails.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +632 to +643
const entries = await Promise.all(
Array.from(projectsByOrg.entries()).map(
async ([orgId, projects]): Promise<[string, OrgProjects]> => {
const org = await this.fetchOrgWithProjects(
accessToken,
cloudRegion,
orgId,
);
return [orgId, { orgName: org?.orgName ?? "(unknown)", projects }];
},
),
);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Superfluous full-org fetch: only orgName is consumed

fetchOrgWithProjects issues a network request to /api/organizations/${orgId}/ and parses the entire teams array — all of which is discarded, since projects in the returned tuple comes from projectsByOrg (the scoped team metas), not from the org call. Consider extracting a thin fetchOrgName helper that skips the teams mapping, or at least skip the call entirely when the org ID can be used as a display label. This follows simplicity rule 4 (no superfluous parts) and avoids the unnecessary allocation on each login.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/code/src/main/services/auth/service.ts
Line: 632-643

Comment:
**Superfluous full-org fetch: only `orgName` is consumed**

`fetchOrgWithProjects` issues a network request to `/api/organizations/${orgId}/` and parses the entire `teams` array — all of which is discarded, since `projects` in the returned tuple comes from `projectsByOrg` (the scoped team metas), not from the org call. Consider extracting a thin `fetchOrgName` helper that skips the `teams` mapping, or at least skip the call entirely when the org ID can be used as a display label. This follows simplicity rule 4 (no superfluous parts) and avoids the unnecessary allocation on each login.

How can I resolve this? If you propose a fix, please make it concise.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@charlesvien charlesvien closed this Jun 4, 2026
@raquelmsmith
Copy link
Copy Markdown
Member Author

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