Skip to content

Enforce corporate_id claim across all Twenty auth paths - #19

Merged
UsamaSadiq merged 2 commits into
foss-sandboxfrom
usama/enforce-corporate-id-auth
Jul 13, 2026
Merged

Enforce corporate_id claim across all Twenty auth paths#19
UsamaSadiq merged 2 commits into
foss-sandboxfrom
usama/enforce-corporate-id-auth

Conversation

@UsamaSadiq

@UsamaSadiq UsamaSadiq commented Jul 9, 2026

Copy link
Copy Markdown
Collaborator

Description

Layer 2 tenant isolation for Twenty: when SMB_CORPORATE_ID is set, every proxy-routed request must carry a Cognito access token with a matching custom:corporate_id claim. This closes the Bearer token bypass gap where SKIP_JWT_BEARER_TOKENS=true in oauth2-proxy validates JWT signatures but not tenant isolation.

Enforcement points (all gated on AUTH_TYPE=SSO + SMB_CORPORATE_ID non-empty):

  • sso-proxy-login.controller.ts -- rejects at login/provisioning time (strictest: missing header = 403)
  • jwt-auth.guard.ts -- rejects stale/mismatched tokens on guarded endpoints
  • middleware.service.ts -- covers hydrateRestRequest and hydrateGraphqlRequest

Non-proxy traffic (MCP OAuth, API-key, internal service calls) does not carry the x-auth-request-access-token header and is silently skipped -- no 403 for paths that never went through oauth2-proxy.

When SMB_CORPORATE_ID is empty/unset (the default), all checks return immediately with no behavioral change.

Testing

  • Verify existing tests pass with SMB_CORPORATE_ID unset (no regression)
  • With SMB_CORPORATE_ID set: browser login with matching corporate_id succeeds, mismatched gets 403
  • MCP and API-key requests continue to work regardless of SMB_CORPORATE_ID setting

When SMB_CORPORATE_ID is set and AUTH_TYPE=SSO, decode the
X-Auth-Request-Access-Token JWT payload and verify
custom:is_corporate="true" and custom:corporate_id matches.
Enforced in MiddlewareService (REST + GraphQL), JwtAuthGuard,
and SsoProxyLoginController. No-op when env var is unset.
@UsamaSadiq
UsamaSadiq force-pushed the usama/enforce-corporate-id-auth branch from 9a7de35 to c90f4b6 Compare July 13, 2026 14:26
Requests without x-auth-request-access-token (MCP OAuth,
API-key, internal) never went through oauth2-proxy and have
no Cognito claims to validate. The middleware/guard paths now
silently skip instead of 403-ing. The proxy-login controller
retains strict enforcement since it is always behind ForwardAuth.
@UsamaSadiq UsamaSadiq changed the title Enforce corporate_id claim in Twenty SSO proxy-login and JWT guard Enforce corporate_id claim across all Twenty auth paths Jul 13, 2026
@UsamaSadiq
UsamaSadiq merged commit f0a325b into foss-sandbox Jul 13, 2026
73 of 76 checks passed
@github-actions

Copy link
Copy Markdown
Fails
🚫

node failed.

Log

Details
�[31mError: �[39m SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON
    at JSON.parse (<anonymous>)
�[90m    at parseJSONFromBytes (node:internal/deps/undici/undici:4387:19)�[39m
�[90m    at successSteps (node:internal/deps/undici/undici:7041:27)�[39m
�[90m    at readAllBytes (node:internal/deps/undici/undici:5958:13)�[39m
�[90m    at process.processTicksAndRejections (node:internal/process/task_queues:104:5)�[39m
danger-results://tmp/danger-results-b8b2a6c8.json

Generated by 🚫 dangerJS against e8d5960

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