Skip to content

feat: Introduce a unified RequestContext for standalone, OIDC, and TrueFoundry authentication - #565

Open
thesujai wants to merge 3 commits into
mainfrom
feat/request-context
Open

feat: Introduce a unified RequestContext for standalone, OIDC, and TrueFoundry authentication#565
thesujai wants to merge 3 commits into
mainfrom
feat/request-context

Conversation

@thesujai

@thesujai thesujai commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Summary

feat: Introduce a unified RequestContext for standalone, OIDC, and TrueFoundry authentication

Closes AGE-2066

Changes

feat: Introduce a unified RequestContext for standalone, OIDC, and TrueFoundry authentication

How was this tested?

MANUALLY and through unit tests

Checklist

  • I have read the contributing guidelines
  • pnpm build, pnpm test, pnpm typecheck, pnpm lint:ci, and pnpm format:check pass locally
  • Tests added/updated where it makes sense
  • No hand-edits to generated code (packages/trueforge-sdk, .github/fern/openapi/openapi.json, docs/openapi.json) — fork PRs omit SDK regen; maintainers regenerate after merge
  • Docs / .env.example updated if configuration or behavior changed

Note

High Risk
Central authentication and authorization refactor with a breaking /auth/me response and tenant-scoped data access across most API surfaces; misconfiguration could affect access control and multi-tenant isolation.

Overview
Introduces a single request-scoped RequestContext (tenant_id, subject, is_admin, optional user_credential) and pluggable Authenticator implementations for standalone, OIDC JWT, and TrueFoundry ServiceFoundry session lookup. Auth middleware is built from the startup-selected authenticator instead of inline OIDC-only logic.

/api/v1/auth/me is a breaking contract change: it now returns { tenant_id, subject: { id, type, display_name }, is_admin } instead of email / role / session type. OpenAPI, SDK types, and docs are updated accordingly.

Protected APIs stop using a hardcoded tenant and UserContext: handlers take resolveRequestContext and scope DB/MCP work with requestContext.tenant_id and requestContext.subject.id (schedules, sessions, settings admin gate via is_admin). TrueFoundry model/MCP stores read the bearer token from user_credential on the context.

OIDC adds configurable OIDC_USER_DISPLAY_NAME_CLAIM (default name, Helm/docs), mapped into subject.display_name with fallback to the user reference claim.

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

@changeset-bot

changeset-bot Bot commented Sep 3, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: e6df9b3

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@truefoundry/trueforge Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Comment thread packages/trueforge/src/schemas/auth.ts
Comment thread packages/trueforge/src/auth/claims.ts Outdated

const { subject } = session.user;
return {
tenant_id: session.user.tenantName,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

TrueFoundry tenant orphans local data

Medium Severity

TrueFoundry auth now scopes every local store read and write to session.user.tenantName. Previously all local rows used the fixed tenant default. Existing agents, sessions, schedules, skills, and sandbox settings stored under default become invisible, with no migration.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 7941001. Configure here.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Correct, will write another PR for that

@thesujai thesujai Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Cant fix this is an expected break cc @chiragjn

@thesujai
thesujai force-pushed the feat/request-context branch from 2d106c3 to e6df9b3 Compare September 3, 2026 05:51

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.

There are 3 total unresolved issues (including 1 from previous review).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit e6df9b3. Configure here.

tenant_id: requestContext.tenant_id,
subject: requestContext.subject,
is_admin: requestContext.is_admin,
};

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Frontend still expects old /me shape

High Severity

GET /auth/me now returns { tenant_id, subject, is_admin } and drops type, but the bundled UI still treats auth.me() as { type: "oidc-connected" }. After a successful OIDC login, isOidcConnectedSession is always false, so the logout control never appears. Schema and SDK changed without the frontend layer.

Additional Locations (1)
Fix in Cursor Fix in Web

Triggered by project rule: TrueForge review rules

Reviewed by Cursor Bugbot for commit e6df9b3. Configure here.

message: 'TrueFoundry ServiceFoundry session response was malformed',
cause: parsed.error,
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Session parse failure returns 500

Low Severity

getSession documents a 502 on ServiceFoundry schema mismatch but throws HTTPException(500). A drifted GET /v1/session body then fails every authenticated TrueFoundry request as an internal server error instead of a bad-gateway/upstream fault.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit e6df9b3. Configure here.

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