Skip to content

Extract OAuth2 flows from OpenAPI security schemes#250

Merged
RhysSullivan merged 6 commits intomainfrom
04-14-extract_oauth2_flows_from_openapi_security_schemes
Apr 15, 2026
Merged

Extract OAuth2 flows from OpenAPI security schemes#250
RhysSullivan merged 6 commits intomainfrom
04-14-extract_oauth2_flows_from_openapi_security_schemes

Conversation

@RhysSullivan
Copy link
Copy Markdown
Owner

Exposes the flows object on components.securitySchemes through the
preview pipeline so the onboarding UI can offer an OAuth2 path for any
spec that declares one. Previously we detected type: oauth2 but
silently dropped the flow metadata, leaving users to paste a bearer
token manually.

Schema additions:

  • OAuth2AuthorizationCodeFlow, OAuth2ClientCredentialsFlow, and
    OAuth2Flows classes capturing authorizationUrl, tokenUrl,
    refreshUrl, and scopes per flow. implicit and password are
    intentionally excluded — both are deprecated by OAuth 2.1 and adding
    them would only encourage users to onboard onto them.
  • SecurityScheme now carries flows, bearerFormat, and
    openIdConnectUrl (previously dropped).
  • OAuth2Preset class — one entry per (scheme × flow) pair with the
    label, URLs, and scope map the onboarding UI needs to render a
    "Connect via OAuth2" flow with a scope checklist.
  • SpecPreview.oauth2Presets carries the derived presets.

Extraction:

  • extractSecuritySchemes now takes a DocResolver and resolves
    $ref entries instead of silently dropping them. Specs that alias
    their security schemes through components.securitySchemes refs
    (rare but real) now surface correctly.
  • extractFlows tolerates malformed flows (missing tokenUrl /
    authorizationUrl) by dropping them, so a broken flow does not
    prevent the rest of the spec from previewing.

5 new tests cover authorizationCode + clientCredentials extraction,
the $ref resolution path, bearerFormat / openIdConnectUrl
capture, and the malformed-flow ignore case.

Generic provider-agnostic helpers for PKCE, authorization URL building,
code exchange, refresh, and the refresh-skew predicate. Locks every
real-world quirk the prior google-discovery oauth.ts handled (string
expires_in, error_description fallback chain, non-JSON 5xx bodies,
empty access_token, 20s timeout, body vs Basic client auth) into a
33-test fidelity suite so future cleanups fail loudly instead of
silently breaking refresh.

Ports google-discovery to use the shared helpers via a thin wrapper
that preserves Google-only authorization params (access_type=offline,
prompt=consent, include_granted_scopes=true) through the extraParams
escape hatch. All existing google-discovery tests still pass.
@cloudflare-workers-and-pages
Copy link
Copy Markdown

cloudflare-workers-and-pages Bot commented Apr 15, 2026

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
executor-marketing 99784f0 Commit Preview URL Apr 15 2026, 06:52 AM

@pkg-pr-new
Copy link
Copy Markdown

pkg-pr-new Bot commented Apr 15, 2026

Open in StackBlitz

@executor/sdk

npm i https://pkg.pr.new/RhysSullivan/executor/@executor/sdk@250

@executor/plugin-file-secrets

npm i https://pkg.pr.new/RhysSullivan/executor/@executor/plugin-file-secrets@250

@executor/plugin-google-discovery

npm i https://pkg.pr.new/RhysSullivan/executor/@executor/plugin-google-discovery@250

@executor/plugin-graphql

npm i https://pkg.pr.new/RhysSullivan/executor/@executor/plugin-graphql@250

@executor/plugin-keychain

npm i https://pkg.pr.new/RhysSullivan/executor/@executor/plugin-keychain@250

@executor/plugin-mcp

npm i https://pkg.pr.new/RhysSullivan/executor/@executor/plugin-mcp@250

@executor/plugin-oauth2

npm i https://pkg.pr.new/RhysSullivan/executor/@executor/plugin-oauth2@250

@executor/plugin-onepassword

npm i https://pkg.pr.new/RhysSullivan/executor/@executor/plugin-onepassword@250

@executor/plugin-openapi

npm i https://pkg.pr.new/RhysSullivan/executor/@executor/plugin-openapi@250

@executor/plugin-workos-vault

npm i https://pkg.pr.new/RhysSullivan/executor/@executor/plugin-workos-vault@250

commit: 99784f0

@RhysSullivan RhysSullivan force-pushed the 04-14-extract_oauth2_flows_from_openapi_security_schemes branch from 967f538 to f9f845a Compare April 15, 2026 00:32
@RhysSullivan RhysSullivan force-pushed the 04-14-add_storeoauthtokens_withrefreshedaccesstoken_refresh_wrapper branch from b100de4 to 61810ab Compare April 15, 2026 00:32
@RhysSullivan RhysSullivan force-pushed the 04-14-extract_oauth2_flows_from_openapi_security_schemes branch from f9f845a to ddab854 Compare April 15, 2026 01:25
@RhysSullivan RhysSullivan force-pushed the 04-14-add_storeoauthtokens_withrefreshedaccesstoken_refresh_wrapper branch from 61810ab to 0ad06ea Compare April 15, 2026 01:25
Split the package into three entrypoints (`.`, `/http`, `/react`) so
browser consumers do not pull Node crypto. New surface:

- `OAuthPopupResult<TAuth>` + `isOAuthPopupResult` in a shared types
  module so both the server-side HTML generator and the client-side
  popup opener agree on the message shape.
- `/http` entry: `popupDocument(payload, channelName)` HTML generator
  (with XSS-safe serialization, dark-mode CSS, postMessage +
  BroadcastChannel fallback), and `runOAuthCallback` wrapper that turns
  a `completeOAuth` Effect into the HTML body for the redirect route.
- `/react` entry: `openOAuthPopup` browser util with centered-popup
  math, same-origin message filtering, settle-once semantics, and
  popup-blocked detection.

Ports `google-discovery` to use them: `api/handlers.ts` drops its
inline `popupDocument` / OAuth glue and becomes a ~20-line handler,
and `AddGoogleDiscoverySource.tsx` drops its inline `openOAuthPopup`.

20 new fidelity tests lock every behavior (XSS escaping, channel name
escape, origin filtering, settle-once across both channels, popup
block handling).
Generic helpers that take a secrets-I/O adapter and a `persistAuth`
callback so plugins can transparently refresh access tokens before a
request without re-implementing the ~150-line token-rotation dance.

- `storeOAuthTokens`: persist a fresh OAuth2TokenResponse as new access
  and (optionally) refresh-token secrets via a `createSecret` callback
  and return a `StoredOAuthTokens` descriptor ready to write to a
  source config.
- `withRefreshedAccessToken`: check `shouldRefreshToken`, resolve
  client/refresh credentials from secrets, call `refreshAccessToken`,
  overwrite the access-token secret in place, optionally rotate the
  refresh-token secret, invoke `persistAuth` with the updated snapshot,
  and return the current access token to be injected into the request.

Ports `google-discovery`:
- `completeOAuth` drops its manual `storeSecret` dance (now a ~15 line
  call to `storeOAuthTokens`).
- `invoke.ts`'s `resolveOAuthAccessToken` shrinks from ~150 lines of
  secret-resolution + refresh + persist glue to ~75 lines of adapter.
- The google-discovery-local `refreshAccessToken` wrapper is removed
  (unused after the port); the google token URL is exported so the
  invoker can pass it to the shared helper.

12 new fidelity tests lock in every branch (no refresh, refresh within
skew, rotated refresh token, preserved refresh token, null refresh ID,
public client without client_secret, secret-resolve failure wrapping).
Exposes the `flows` object on `components.securitySchemes` through the
preview pipeline so the onboarding UI can offer an OAuth2 path for any
spec that declares one. Previously we detected `type: oauth2` but
silently dropped the flow metadata, leaving users to paste a bearer
token manually.

Schema additions:
- `OAuth2AuthorizationCodeFlow`, `OAuth2ClientCredentialsFlow`, and
  `OAuth2Flows` classes capturing `authorizationUrl`, `tokenUrl`,
  `refreshUrl`, and `scopes` per flow. `implicit` and `password` are
  intentionally excluded — both are deprecated by OAuth 2.1 and adding
  them would only encourage users to onboard onto them.
- `SecurityScheme` now carries `flows`, `bearerFormat`, and
  `openIdConnectUrl` (previously dropped).
- `OAuth2Preset` class — one entry per (scheme × flow) pair with the
  label, URLs, and scope map the onboarding UI needs to render a
  "Connect via OAuth2" flow with a scope checklist.
- `SpecPreview.oauth2Presets` carries the derived presets.

Extraction:
- `extractSecuritySchemes` now takes a `DocResolver` and resolves
  `$ref` entries instead of silently dropping them. Specs that alias
  their security schemes through `components.securitySchemes` refs
  (rare but real) now surface correctly.
- `extractFlows` tolerates malformed flows (missing `tokenUrl` /
  `authorizationUrl`) by dropping them, so a broken flow does not
  prevent the rest of the spec from previewing.

5 new tests cover authorizationCode + clientCredentials extraction,
the `$ref` resolution path, `bearerFormat` / `openIdConnectUrl`
capture, and the malformed-flow ignore case.
@RhysSullivan RhysSullivan force-pushed the 04-14-add_storeoauthtokens_withrefreshedaccesstoken_refresh_wrapper branch from 0ad06ea to ef43334 Compare April 15, 2026 02:12
@RhysSullivan RhysSullivan force-pushed the 04-14-extract_oauth2_flows_from_openapi_security_schemes branch from ddab854 to 12433ef Compare April 15, 2026 02:12
@RhysSullivan RhysSullivan marked this pull request as ready for review April 15, 2026 06:39
Copy link
Copy Markdown
Owner Author

RhysSullivan commented Apr 15, 2026

Merge activity

  • Apr 15, 6:43 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Apr 15, 6:49 AM UTC: Graphite couldn't merge this PR because it had merge conflicts.
  • Apr 15, 6:05 PM UTC: A user started a stack merge that includes this pull request via Graphite.

@RhysSullivan RhysSullivan changed the base branch from 04-14-add_storeoauthtokens_withrefreshedaccesstoken_refresh_wrapper to graphite-base/250 April 15, 2026 06:46
@RhysSullivan RhysSullivan changed the base branch from graphite-base/250 to main April 15, 2026 06:47
@RhysSullivan RhysSullivan merged commit bb6dfa5 into main Apr 15, 2026
6 of 7 checks passed
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