Skip to content

refactor(oauth): share authorization attempts across OAuth flows - #14122

Merged
wenxi-onyx merged 3 commits into
mainfrom
whuang/oauth-authorization-attempts
Aug 21, 2026
Merged

refactor(oauth): share authorization attempts across OAuth flows#14122
wenxi-onyx merged 3 commits into
mainfrom
whuang/oauth-authorization-attempts

Conversation

@wenxi-onyx

@wenxi-onyx wenxi-onyx commented Aug 20, 2026

Copy link
Copy Markdown
Member

Description

Why this is needed

OAuth authorization starts in one request and finishes later in a browser callback. During that gap, the server must remember who started the flow, where to return them, and—when PKCE is used—the secret verifier needed to finish safely.

That temporary state must work across API replicas, expire automatically, and be usable only once. The connector flow did not have one shared mechanism with all of those guarantees, which made concurrent callbacks and multi-replica deployments harder to reason about.

How it works

This PR adds a small, shared authorization-attempt store backed by Onyx's configured cache. Each attempt:

  • has an opaque, collision-safe state value;
  • is scoped to the tenant, OAuth flow, and initiating user;
  • expires after a short time; and
  • is claimed atomically, so only one callback can complete it.

The connector OAuth flow is the first consumer. Its PKCE verifier now stays on the server instead of in the browser, and its callback verifies the initiating user before using the attempt. The cache gains the two standard atomic operations needed to support this with either Redis or PostgreSQL.

Why this design

The reusable part of OAuth is the authorization-attempt lifecycle—not provider-specific requests, token mapping, or credential storage. Keeping that boundary narrow gives later MCP, external-app, federated-connector, and action OAuth flows the same safety guarantees without forcing their different domain logic into one large framework.

Starting with connectors keeps this foundation reviewable and proves it with a complete, smaller consumer. PR #14123 builds directly on it for the more involved MCP flow.

How Has This Been Tested?

Additional Options

  • [Optional] Please cherry-pick this PR to the latest release version.
  • [Optional] Override Linear Check

@greptile-apps

greptile-apps Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR adds a tenant-scoped, typed, one-time authorization-attempt store and migrates connector OAuth state and PKCE verifier storage to the configured cache.

  • Adds atomic get-and-delete and set-if-absent operations for Redis and PostgreSQL cache backends.
  • Binds OAuth attempts to the connector namespace and initiating user.
  • Validates and normalizes callback return paths before redirecting.
  • Updates frontend URL construction and adds focused backend and frontend coverage.

Confidence Score: 5/5

The PR appears safe to merge with no concrete blocking or non-blocking defects identified.

The cache implementations satisfy the expanded interface, preserve tenant isolation and atomic one-time semantics, and the migrated OAuth flow consistently validates ownership, connector scope, expiry, PKCE data, and local return paths.

Important Files Changed

Filename Overview
backend/onyx/cache/interface.py Adds atomic consume and conditional-set operations to the cache contract; all repository implementations were updated.
backend/onyx/cache/postgres_backend.py Implements both cache primitives with tenant-scoped atomic PostgreSQL statements and expiry-aware conflict handling.
backend/onyx/cache/redis_backend.py Delegates atomic consumption to GETDEL and collision prevention to SET NX.
backend/onyx/oauth/authorization_attempt.py Introduces validated, owner-bound, namespaced, expiring authorization attempts with atomic one-time consumption.
backend/onyx/oauth/models.py Defines the frozen generic authorization-attempt envelope and its expiry contract.
backend/onyx/server/documents/standard_oauth.py Migrates connector OAuth state and PKCE continuation to the shared cache abstraction and validates callback return paths.
web/src/lib/connectors/oauth.ts Sends the current local path, query, and fragment instead of the full browser URL.

Sequence Diagram

sequenceDiagram
  participant Browser
  participant API as Connector OAuth API
  participant Cache as Tenant Cache
  participant Provider as OAuth Provider
  Browser->>API: Authorize(source, local return path)
  API->>Cache: SET NX(owner, source, state, payload, TTL)
  API-->>Browser: Provider authorization URL
  Browser->>Provider: Authorize with state and PKCE challenge
  Provider-->>Browser: Callback(code, state)
  Browser->>API: Callback(code, state)
  API->>Cache: Atomic GETDEL(owner, source, state)
  API->>Provider: Exchange code and PKCE verifier
  API-->>Browser: Redirect with credentialId
Loading

Reviews (1): Last reviewed commit: "refactor(oauth): share connector authori..." | Re-trigger Greptile

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 17119bde88

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread backend/onyx/cache/postgres_backend.py
Comment thread backend/onyx/server/documents/standard_oauth.py

@cubic-dev-ai cubic-dev-ai 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.

All reported issues were addressed across 17 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread backend/onyx/oauth/models.py Outdated
@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

🖼️ Visual Regression Report

Project Changed Added Removed Unchanged Report
admin 2 0 0 185 View Report
exclusive 0 0 0 10 ✅ No changes

@evan-onyx evan-onyx 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.

In general I like the approach. I think for a PR like this we might want more E2E tests to get confidence

@wenxi-onyx
wenxi-onyx force-pushed the whuang/oauth-authorization-attempts branch from edbda6d to cbe94d6 Compare August 20, 2026 23:03
@github-actions

github-actions Bot commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

Preview Deployment

Status Preview Commit Updated
https://onyx-preview-rklc6fwca-danswer.vercel.app 235e767 2026-08-20 23:21:36 UTC

@wenxi-onyx
wenxi-onyx force-pushed the whuang/oauth-authorization-attempts branch from cbe94d6 to 235e767 Compare August 20, 2026 23:17
@wenxi-onyx
wenxi-onyx added this pull request to the merge queue Aug 21, 2026
Merged via the queue into main with commit 14673a2 Aug 21, 2026
194 of 196 checks passed
@wenxi-onyx
wenxi-onyx deleted the whuang/oauth-authorization-attempts branch August 21, 2026 02:21
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