Skip to content

feat(auth): add scoped OAuth access and browser-based CLI login - #7488

Merged
waleedlatif1 merged 22 commits into
stagingfrom
feat/oauth-provider
Sep 8, 2026
Merged

feat(auth): add scoped OAuth access and browser-based CLI login#7488
waleedlatif1 merged 22 commits into
stagingfrom
feat/oauth-provider

Conversation

@waleedlatif1

@waleedlatif1 waleedlatif1 commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator

Adds delegated OAuth access for the CLI and operator-registered applications. sim login uses authorization code + PKCE with short-lived opaque access tokens, rotating refresh tokens, explicit consent, and immediate revocation. Existing API keys, session login, connector OAuth linking, and the browserless CLI pairing flow remain supported.

Authorization and lifecycle

  • OAuth credentials enter the same application operations and current membership checks as personal API keys. Each operation explicitly declares api:read or api:write, independently of its minimum workspace role and HTTP method. Searches can be read-only POSTs; execution and external discovery require write access.
  • Token families isolate independent logins, enforce a fixed lifetime and bounded rotation history, and revoke on refresh-token reuse. Consent narrowing, revocation, concurrent issuance, and failure compensation are transactional and covered against real PostgreSQL.
  • Dynamic client registration and plugin client-management endpoints remain disabled. OIDC is disabled; the provider grants only offline_access, api:read, and api:write.
  • Discovery, authorization, consent, token endpoints, and bearer access honor the global AppConfig oauth-provider flag at request time. The existing environment variable is only a fallback when AppConfig has no document. Existing connector /oauth2/link and callback routes continue to work with the provider enabled or disabled.

Browser and CLI

  • Consent uses the shared auth shell with one logo, clear permissions, account switching, and pending/error states. Approval and cancellation use the same shared connection page. CLI consent omits the extra disclaimer.
  • Login/signup continuations preserve OAuth parameters and use the configured auth origin, including reauthentication with existing or stale cookies.
  • Authorized apps is available in unified workspace settings and account settings. Server search and keyset pagination bound each read; revocation removes all grants and token families for the application.
  • CLI credentials use proper-lockfile with async-context reentrancy. Separate-process tests cover competing refreshes and refresh/logout ordering. OAuth response bodies are byte-capped, and bundled dependency declarations and license notices are complete.
  • OpenAPI derives scopes from the canonical operation objects; tests compare all 220 documented policies with runtime route declarations. SDK authentication remains API-key based.

Deployment

Requires PostgreSQL 15+. SQL migration 0323 adds the OAuth schema after staging’s existing migrations. Script migration 0012 installs the shared trigger and CLI-registration lifecycle; db:push invokes the same idempotent reconciler. Reapplication preserves existing grants and operator customizations. Both fresh provisioning paths now run in dedicated PostgreSQL CI jobs.

Enable the global oauth-provider AppConfig entry after migrations are applied and older app instances have drained. Better Auth registers the provider once and request-time guards cover its direct calls and authorization continuations, so runtime changes need no restart.

OAuth cleanup is scheduled in Docker and Helm, with small family transactions, independent access-token pages, and a shared time budget.

Verification

  • Full app suite: 42,489 passed; full CLI suite: 924 passed; DB suite: 120 passed.
  • All 46 repository audits and 26 type-check tasks passed. OpenAPI validates 223 contracts and 664 examples; each documented route matches its runtime operation policy.
  • Fresh PostgreSQL db:push, full db:migrate, and migration replay passed; all 12 provider lifecycle integration tests passed on both provisioning paths.
  • Live browser + built CLI: sign-in, consent approval/denial, account switching, shared completion page, phone-width layouts, token refresh, read-only write rejection, successful writes and workflow execution with both OAuth and personal API keys, settings revocation, and subsequent CLI rejection.
  • Live disabled-provider check: OAuth bearer 401 and discovery 404, while API keys and session login still work and connector linking reaches provider validation.
  • Live AppConfig protocol check: off → on → off without restarting the app, with an enabled environment fallback proving AppConfig takes precedence. API-key access, session login, and connector provider validation remain functional while disabled.
  • Latest staging merged; affected staging tests and checks rerun. External connector account linking was checked through provider validation and regression tests; no live third-party credentials were used.

Sim becomes an authorization server, so other software can sign a person in
and act as them with their consent. `sim login` uses it by default, replacing
a permanent personal API key with a short-lived, scoped, revocable token.

Built on `@better-auth/oauth-provider@1.6.27`, pinned to match the Better Auth
already in the tree — no upgrade required.

Tokens are opaque rather than JWTs, so revoking an app in settings or running
`sim logout` takes effect on the very next request. Access tokens last an
hour; refresh tokens rotate on every use and expire after thirty days.

A new principal kind, `oauth_access_token`, is admitted exactly where
`personal_api_key` is and nowhere else; `check:principal-kind-parity` fails
the build if the two ever drift apart. Write scope is derived from the HTTP
method at v2 admission rather than from an operation's `minimumRole`, because
several POST routes only read — a role-derived rule let a read-only token
write.

The consent card refuses to render for a request Sim did not issue: an
unsigned query, a repeated parameter, or a client the server declines to name.

Clients are operator-created rows. Dynamic registration is off, and every one
of the plugin's client CRUD endpoints is closed at the source.

Off with `OAUTH_PROVIDER_ENABLED=false`, which the CLI detects and falls back
to the existing pairing-code handoff.
@vercel

vercel Bot commented Sep 4, 2026

Copy link
Copy Markdown

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

Project Deployment Actions Updated
docs Ready Ready Preview Sep 8, 2026 12:12am UTC

Request Review

@waleedlatif1
waleedlatif1 marked this pull request as ready for review September 5, 2026 01:43
@waleedlatif1
waleedlatif1 requested a review from a team as a code owner September 5, 2026 01:43
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile-apps review this PR

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile-apps review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@greptile-apps

greptile-apps Bot commented Sep 5, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

Adds delegated OAuth authorization for CLI and registered applications while preserving existing API-key, session, connector-linking, and browserless authentication flows.

  • Introduces authorization-code login with PKCE, scoped access tokens, rotating refresh-token families, consent, revocation, and provider feature gating.
  • Integrates OAuth principals and explicit read/write scopes into application-operation authorization.
  • Adds browser consent, authorized-app settings, CLI credential locking and refresh behavior, token cleanup, PostgreSQL migrations, deployment configuration, documentation, and extensive tests.
  • No code has changed since the previous review.

Confidence Score: 5/5

The PR appears safe to merge because no outstanding correctness, security, or repository-rule failures remain.

The previous refresh-token downscoping concern was correctly withdrawn after confirming the RFC-defined behavior, and the resolved consent-component thread does not represent a violation of the repository’s current component convention. No changes were made after the previous review, and no accepted new findings remain.

Important Files Changed

Filename Overview
apps/sim/lib/auth/oauth-token-family.ts Implements bounded OAuth token-family rotation, refresh-token reuse handling, lifetime enforcement, and revocation.
apps/sim/lib/auth/oauth-provider.ts Configures the scoped OAuth provider and its supported grants, clients, and lifecycle behavior.
apps/sim/lib/core/application/oauth-authorization.ts Applies OAuth scope authorization alongside existing application-operation and workspace-role checks.
packages/sim-cli/src/auth/oauth-flow.ts Implements browser-based CLI authorization-code login with PKCE and loopback callback handling.
packages/sim-cli/src/auth/refresh.ts Coordinates credential locking and refresh-token rotation across concurrent CLI processes.
packages/db/migrations/0323_oauth_provider.sql Adds the persistent OAuth grants, clients, access tokens, refresh tokens, and lifecycle schema.
apps/sim/app/(auth)/oauth/consent/consent-view.tsx Renders OAuth consent and approval states using the existing authentication UI conventions.

Sequence Diagram

sequenceDiagram
  participant CLI
  participant Browser
  participant OAuth as Sim OAuth Provider
  participant DB as PostgreSQL
  participant API as Sim API

  CLI->>CLI: Generate PKCE verifier and challenge
  CLI->>Browser: Open authorization request
  Browser->>OAuth: Authenticate and review consent
  OAuth->>DB: Persist grant and token family
  OAuth-->>Browser: Redirect with authorization code
  Browser-->>CLI: Deliver code to loopback callback
  CLI->>OAuth: Exchange code and PKCE verifier
  OAuth->>DB: Validate code and issue tokens
  OAuth-->>CLI: Access and refresh tokens
  CLI->>API: Bearer access token
  API->>DB: Validate token, scopes, and membership
  API-->>CLI: Scoped operation response
  CLI->>OAuth: Rotate refresh token when needed
  OAuth->>DB: Consume old token and store replacement
  OAuth-->>CLI: New access and refresh tokens
Loading

Reviews (7): Last reviewed commit: "Merge remote-tracking branch 'origin/sta..." | Re-trigger Greptile

Comment thread apps/sim/lib/auth/oauth-token-family.ts
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@waleedlatif1 waleedlatif1 changed the title feat(auth): make Sim an OAuth 2.1 provider and move the CLI onto it feat(auth): add scoped OAuth access and browser-based CLI login Sep 7, 2026
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

Comment thread apps/sim/app/(auth)/oauth/consent/consent-view.tsx
@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1

Copy link
Copy Markdown
Collaborator Author

@cubic-dev-ai review this PR

@cubic-dev-ai

cubic-dev-ai Bot commented Sep 8, 2026

Copy link
Copy Markdown
Contributor

@cubic-dev-ai review this PR

@waleedlatif1 I have started the AI code review. It will take a few minutes to complete.

@waleedlatif1
waleedlatif1 merged commit 8adb986 into staging Sep 8, 2026
41 of 42 checks passed
waleedlatif1 added a commit that referenced this pull request Sep 8, 2026
Brings PR #7488 (OAuth provider) under the SCIM branch so #7567 can target it.

- SCIM migration renumbered to 0324_scim_provisioning after the OAuth
  branch's 0323; regenerated from the merged schema (identical apart from
  the number).
- Forbidden detail codes keep both INSUFFICIENT_SCOPE and
  SCIM_MANAGED_MEMBERSHIP; OpenAPI docs regenerated.
- SCIM ships with the enterprise plan on the hosted product: the outer gate
  is now isScimDeploymentEnabled() (hosted, or SCIM_ENABLED / ENTERPRISE_ENABLED
  self-hosted) and the plan check stays per organization. The env variable
  remains the self-hosted switch and is bundled under ENTERPRISE_ENABLED.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DGXcwsHzYGp6pUDWRtJKpz
waleedlatif1 added a commit that referenced this pull request Sep 8, 2026
#7488 landed on staging as a squash, so the branch now carries staging
itself. Same resolutions as the OAuth merge: both forbidden detail codes,
OpenAPI regenerated, chart 1.10.0, journal keeps 0323_oauth_provider then
0324_scim_provisioning.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DGXcwsHzYGp6pUDWRtJKpz
@waleedlatif1
waleedlatif1 deleted the feat/oauth-provider branch September 8, 2026 01:12
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