Skip to content

fix(auth): reject PAT and service user when parent org is disabled#1792

Merged
whoAbhishekSah merged 4 commits into
mainfrom
fix/auth-reject-disabled-org-credentials
Jul 23, 2026
Merged

fix(auth): reject PAT and service user when parent org is disabled#1792
whoAbhishekSah merged 4 commits into
mainfrom
fix/auth-reject-disabled-org-credentials

Conversation

@whoAbhishekSah

@whoAbhishekSah whoAbhishekSah commented Jul 23, 2026

Copy link
Copy Markdown
Member

Part of #1585.

Problem

A PAT or service user tied to a disabled org keeps authenticating.

Fix

Once a PAT or service user is resolved, GetPrincipal checks the parent org in one place. A disabled or missing org returns 403 Forbidden. The missing-org case also covers service users left orphaned by a deleted org.

The check sits at the auth boundary, not inside the shared service Get methods, so admin and list views can still surface principals from disabled orgs. The platform org (used by the bootstrap superuser) is skipped, so break-glass credentials keep working.

Testing

Verified live against a local server. Probe RPC: FrontierService/GetCurrentUser (it fails at the auth boundary, so its status reflects the gate directly). The org was disabled with FrontierService/DisableOrganization as the bootstrap superuser.

credential (auth path) before disable after disable
PAT — Bearer (authenticateWithPAT) 200 403
service user — Basic client credentials (authenticateWithClientCredentials) 200 403
bootstrap superuser — platform org 200 200

Opaque service-user tokens (CreateServiceUserToken) authenticate through the same client-credentials path, and every authenticator funnels through the single GetPrincipal check.

Unit tests cover disabled-org, missing-org, and empty-org for PAT and both service-user paths, plus IsEnabled for enabled / disabled / missing / unexpected-error.

🤖 Generated with Claude Code

Disabling an org flipped its state but left credentials owned by that
org working. The PAT and service-user auth paths fetched the principal
without looking at the org state.

Each PAT and service-user authenticator now checks the parent org
through a new organization.IsEnabled. A disabled or missing org returns
403. The platform org (bootstrap superuser) is skipped so break-glass
credentials keep working.

Part of #1585.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 23, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated (UTC)
frontier Ready Ready Preview, Comment Jul 23, 2026 6:50am

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@whoAbhishekSah, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 19 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 99bf2e33-c9a8-4001-bc3a-1263fba484be

📥 Commits

Reviewing files that changed from the base of the PR and between 0b3f533 and e0f3a08.

📒 Files selected for processing (4)
  • core/authenticate/authenticators.go
  • core/authenticate/service.go
  • core/authenticate/service_test.go
  • core/organization/service_test.go
📝 Walkthrough

Walkthrough

Changes

Organization authentication gating

Layer / File(s) Summary
Organization enablement contract
core/organization/service.go, core/organization/service_test.go
Adds IsEnabled to distinguish enabled, disabled, missing, and unexpected organization lookup results.
Authentication principal state gate
core/authenticate/service.go, core/authenticate/authenticators.go, core/authenticate/mocks/*, cmd/serve.go, core/authenticate/service_test.go, internal/api/v1beta1connect/authenticate.go
Injects the organization service, checks organization state across authentication flows, tests disabled and enabled cases, and maps forbidden results to permission-denied responses.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related issues

Possibly related PRs

Suggested reviewers: rohilsurana

🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 91a8ec78-77cf-43e9-8d72-70e6b345b9b7

📥 Commits

Reviewing files that changed from the base of the PR and between c99f1f8 and 417ee4d.

📒 Files selected for processing (8)
  • cmd/serve.go
  • core/authenticate/authenticators.go
  • core/authenticate/mocks/org_service.go
  • core/authenticate/service.go
  • core/authenticate/service_test.go
  • core/organization/service.go
  • core/organization/service_test.go
  • internal/api/v1beta1connect/authenticate.go

Comment thread core/authenticate/authenticators.go
@coveralls

coveralls commented Jul 23, 2026

Copy link
Copy Markdown

Coverage Report for CI Build 29986303562

Warning

No base build found for commit c99f1f8 on main.
Coverage changes can't be calculated without a base build.
If a base build is processing, this comment will update automatically when it completes.

Coverage: 46.266%

Details

  • Patch coverage: 5 uncovered changes across 3 files (39 of 44 lines covered, 88.64%).

Uncovered Changes

File Changed Covered %
core/authenticate/authenticators.go 26 24 92.31%
internal/api/v1beta1connect/authenticate.go 2 0 0.0%
cmd/serve.go 1 0 0.0%
Total (5 files) 44 39 88.64%

Coverage Regressions

Requires a base build to compare against. How to fix this →


Coverage Stats

Coverage Status
Relevant Lines: 38581
Covered Lines: 17850
Line Coverage: 46.27%
Coverage Strength: 14.08 hits per line

💛 - Coveralls

An empty org id skipped the gate, so a PAT or service user with no
resolvable org would authenticate. Return 403 for an empty id; only the
platform org (a fixed UUID) is exempt.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Move the parent-org check out of the individual authenticators into a
single point in GetPrincipal, keyed off the resolved principal type.
Same behavior, one check instead of five, and any future authenticator
that returns a PAT or service user principal is covered automatically.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Use func() setup closures that capture the outer t (matching the
existing GetPrincipal table) and add t.Helper() to the org test helper.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@whoAbhishekSah
whoAbhishekSah merged commit a0618e0 into main Jul 23, 2026
8 checks passed
@whoAbhishekSah
whoAbhishekSah deleted the fix/auth-reject-disabled-org-credentials branch July 23, 2026 14:08
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.

3 participants