Skip to content

fix(provider): ask for an OAuth client ID when Coral cannot register one - #2580

Merged
iaptsiauri merged 3 commits into
mainfrom
fix/reef-oauth-signin-without-application
Oct 21, 2026
Merged

iaptsiauri merged 3 commits into
mainfrom
fix/reef-oauth-signin-without-application

Conversation

@iaptsiauri

@iaptsiauri iaptsiauri commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Summary

An agent could call createProvider with an OAuth Provider Configuration that names no OAuth application, for a service Coral cannot register one with (no Dynamic Client Registration or Client ID Metadata Document, such as Google), or for device authorization. Coral returned needs_sign_in. The person's sign-in then failed, and Reef showed only "Coral is not available."

createProvider now refuses the call, and the agent can correct it:

 createProvider
   prepare Setup, confirm Provider Configuration
   SetupPublishability
     Coral  → publish
+    Person, and the sign-in has no OAuth application
+      → end the Setup
+      → invalid_input at `authentication.client`:
+        "Coral cannot register an OAuth application with this service;
+         register one with the service and give its `client_id`"
     Person → needs_sign_in + Reef link
has_oauth_application(authentication)
  oauth_authorization_code without client → can Coral set one up for this Setup?
  oauth_device_code without client        → no (Coral never sets one up)
  anything else                           → yes

An older Coral server can still confirm such a configuration. Reef handles that case:

 attemptProgress
   stage
+    confirmed configuration, OAuth sign-in not started, no application,
+    and Coral cannot set one up                    → configuration
 <AccountStep>
-  <Button "Sign in with …" disabled={pending}>
+  <Button "Sign in with …" disabled={pending || no application}>
 <ManagementErrorBoundary>
-  any other status → "Coral is unavailable. Reload the page to try again."
+  400 / 409 with a body → Reef's reason
+  other 4xx             → "Coral cannot complete this request. Go back to the previous page."
+  5xx                   → "Coral is unavailable. Reload the page to try again."

The configuration hint now reads "Enter the client ID of your OAuth application in configuration before you sign in."

isOAuthMethod and automaticApplicationAllowed replace four inline copies of those checks in Reef. TestModules::accounts() replaces four copies of the filesystem-vault setup in the coral-run tests.

Evidence

The new tests ran against main's source (tests from this branch), then against this branch:

  • Before: cargo test -p coral-run --lib an_invalid_argument_names_what_to_correct fails. The OAuth case with no client returns {"status": "needs_sign_in", "url": "…/providers/new?setup=…"}, not invalid_input.
    After: passes for both the authorization-code case and the device-code case. Each denial also asserts it published nothing and canceled every Setup it prepared.

  • Before: Reef Vitest fails 9 cases:

    • model.test.ts: the agent's link for an MCP, API or device sign-in Coral cannot set up opens discovery / operations, not configuration
    • account-step.test.tsx: "Sign in with Gmail" is enabled for the shared account and for your own account
    • management-error.test.tsx: a 400 or 409 shows "Coral is unavailable"
    • oauth-application.test.tsx: the old hint copy

    After: all 66 cases in those four files pass.

  • Gates on this branch, rebased on main:

    • Rust: make rust-checks passes, 1469 of 1469 (6 skipped).
    • Reef: npm run check, typecheck, npm test (1644 + 661 pass) and build pass. test:server has 15 pass and 1 fail, in scripts/bundle-server.test.mjs ('hello bundle' vs 'hello staged'). This PR does not touch that file. feat(reef): make the providers rail vertical tabs with an All providers entry #2552 reported the same failure.
    • Not run: make postgres-tests. No repository code changes.

Merge Danger

Door: two-way

No schema, stored data or API shape changes. Revert restores the old needs_sign_in answer.

Blast Radius: provider-setup

Agents that call createProvider with OAuth and no client for a service without automatic registration now get invalid_input, not a Reef link. That link led to a sign-in that could not start. Management pages that end in a 4xx other than 401, 403 or 404 now say the request failed, not that Coral is unavailable.

createProvider accepted an OAuth configuration that named no client for a
service without Dynamic Client Registration or a Client ID Metadata
Document, and for device authorization. It returned needs_sign_in, and the
person's sign-in then failed with "Coral is not available." It now refuses
the call at `authentication.client` and ends the Setup it prepared.

Reef sends a Setup an older Coral confirmed that way back to configuration,
disables the sign-in button, and shows Reef's own reason for a 400 or 409
instead of saying Coral is unavailable.
@iaptsiauri
iaptsiauri force-pushed the fix/reef-oauth-signin-without-application branch from 7ef7c43 to ca8de7f Compare October 21, 2026 12:26

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

Review completed against the latest diff

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

Re-trigger cubic

Comment thread apps/reef/app/views/management/management-error.tsx
Comment thread apps/reef/app/views/management/management-error.tsx
Comment thread apps/reef/app/views/management/management-error.test.tsx Outdated
iaptsiauri and others added 2 commits October 21, 2026 15:29
Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com>
@iaptsiauri
iaptsiauri merged commit baefe9e into main Oct 21, 2026
25 checks passed
@iaptsiauri
iaptsiauri deleted the fix/reef-oauth-signin-without-application branch October 21, 2026 12:49
simonwhitaker pushed a commit that referenced this pull request Oct 22, 2026
🤖 I have created a release *beep* *boop*
---


## [1.2.0](v1.1.0...v1.2.0)
(2026-10-22)


### Features

* **activity:** record authored source locations for calls and outputs
([#2535](#2535))
([2d735ca](2d735ca))
* **activity:** show persistent Program source beside selected records
([#2569](#2569))
([f403819](f403819))
* add the Claude recipe and read gzipped OpenAPI documents
([#2513](#2513))
([07c27a2](07c27a2))
* **catalog:** share named TypeScript types across a Provider
([#2482](#2482))
([256e37d](256e37d))
* **desktop:** run the runtime on a Postgres database named in
desktop.json ([#2485](#2485))
([96465a0](96465a0))
* **functions:** type coral.providers, coral.workspace and
coral.functions at Saved Function save
([#2526](#2526))
([a465850](a465850))
* **provider:** create the Coral Built-in Provider at coral.workspace in
every new Workspace
([#2349](#2349))
([06e65ca](06e65ca))
* **provider:** store an agent's createProvider request on its Setup
([#2593](#2593))
([92847d2](92847d2))
* **provider:** update every Workspace's Built-in Provider catalog at
boot ([#2355](#2355))
([24615d9](24615d9))
* **reef:** add NextDNS provider recipe
([#2509](#2509))
([e44880e](e44880e))
* **reef:** calmer providers table and a flush app shell
([#2462](#2462))
([ffe279c](ffe279c))
* **reef:** improve the UI on small screens
([#2531](#2531))
([75e020a](75e020a))
* **reef:** make the providers rail vertical tabs with an All providers
entry ([#2552](#2552))
([08d007a](08d007a))
* **reef:** providers page UI tweaks
([#2562](#2562))
([7ca218e](7ca218e))
* **reef:** put the list pages' main action back in the top bar as a
primary button ([#2546](#2546))
([761ea6d](761ea6d))
* **reef:** read ^, $ and * in every filter field
([#2520](#2520))
([d322356](d322356))
* **reef:** refuse a provider display name another provider uses
([#2518](#2518))
([fdcd473](fdcd473))
* **reef:** review provider configuration changes in a dialog
([#2579](#2579))
([24417e9](24417e9))
* **reef:** show search indexing failures on a Provider and its
Operations ([#2504](#2504))
([6cffed0](6cffed0))
* **reef:** show your recent activity summary on the workspace overview
([#2574](#2574))
([0d1dba5](0d1dba5))
* **reef:** title list pages in their toolbar, with the main action
beside it ([#2525](#2525))
([fd44b72](fd44b72))
* **reef:** UI tweaks to provider's page
([#2566](#2566))
([62204ca](62204ca))
* **reef:** unify Activity detail panels and action reviews
([#2544](#2544))
([409d062](409d062))
* return only declared successes from Operation calls
([#2517](#2517))
([0270bf1](0270bf1))
* **run:** enforce the Fan-out Limit inside the Run Owner
([#2571](#2571))
([cb53419](cb53419))
* **run:** introduce the Run Owner for Program requests
([#2524](#2524))
([245d19d](245d19d))
* **run:** let coral.workspace.createProvider configure and publish the
Provider itself
([#2352](#2352))
([088faaf](088faaf))
* **run:** let createProvider configure sign-in and link to Reef's
sign-in step ([#2353](#2353))
([8d5495c](8d5495c))
* **run:** list a workspace's providers with
coral.workspace.listProviders
([#2374](#2374))
([179c43a](179c43a))
* **run:** make the Run Owner survive uncertain commits and lost leases
([#2541](#2541))
([3a1fad1](3a1fad1))
* **run:** name Tasks and Runs with four-word identifiers
([#2558](#2558))
([c82259a](c82259a))
* **run:** prepare a Provider from a Program with
coral.workspace.createProvider
([#2351](#2351))
([e7e56fd](e7e56fd))
* **run:** reshape the Dispatch Fence into one batched check per chunk
commit ([#2550](#2550))
([120c9d3](120c9d3))
* **run:** route approval decisions and cancellation through the Run
Owner ([#2577](#2577))
([77bcbf5](77bcbf5))
* **run:** summarize your recent activity in a Workspace
([#2573](#2573))
([bf4c75e](bf4c75e))
* **search:** show a Saved Function's result fields in its signature
line ([#2522](#2522))
([41365f6](41365f6))
* **search:** trace each reconcile pass and its steps
([#2456](#2456))
([0594094](0594094))
* **ui:** add option to create a correctly-configured Slack app during
Slack provider setup
([#2585](#2585))
([8c3a883](8c3a883))
* **ui:** move Add provider to the providers toolbar
([#2591](#2591))
([e1ee4cb](e1ee4cb))


### Bug Fixes

* **app:** sweep device authorization leases every 15 s
([#2452](#2452))
([1a4e4ae](1a4e4ae))
* **auth:** drop the unverified client name note from the approval page
([#2578](#2578))
([ddf5aa4](ddf5aa4))
* **catalog:** derive each Built-in Operation's contract from the types
Coral parses ([#2582](#2582))
([534e636](534e636))
* **catalog:** import OpenAPI Providers whose Operations request
different OAuth scopes
([#2401](#2401))
([3acfe55](3acfe55))
* **catalog:** keep keyword names in Operation Call Paths
([#2506](#2506))
([b20795b](b20795b))
* **catalog:** never make an Operation unavailable for search material
([#2465](#2465))
([f83c909](f83c909))
* **catalog:** stop rejecting createProvider request headers by name
([#2589](#2589))
([39e54b9](39e54b9))
* **provider:** ask for an OAuth client ID when Coral cannot register
one ([#2580](#2580))
([baefe9e](baefe9e))
* **provider:** bind each Setup to its starter and hide Coral from
Members ([#2480](#2480))
([6011a64](6011a64))
* **reef:** align the catalog table with the first rail entry
([#2484](#2484))
([fb59758](fb59758))
* **reef:** calm the Activity badge and keep it while the stream
reconnects ([#2468](#2468))
([1b66639](1b66639))
* **reef:** frame the providers table again and lower the top bar
([#2472](#2472))
([87e41ee](87e41ee))
* **reef:** pin third-party recipe OpenAPI documents to a commit
([#2510](#2510))
([b4e9280](b4e9280))
* **reef:** replace loose help text with info tips and banners
([#2461](#2461))
([695500a](695500a))
* **reef:** round the page's corners beside the sidebar
([#2503](#2503))
([a1fef64](a1fef64))
* **reef:** shorten OAuth scope chips that share a URL prefix
([#2455](#2455))
([5ae67ec](5ae67ec))
* **reef:** suggest a provider's namespace from its document name, not
its host ([#2565](#2565))
([8d77893](8d77893))
* **run:** name every argument to correct in an invalid_input failure
([#2354](#2354))
([07bd727](07bd727))
* **run:** reject a credential beside createProvider's bearer method and
report unreachable sources as upstream_incomplete
([#2542](#2542))
([590eab7](590eab7))
* **run:** report an MCP JSON-RPC rejection as invalid_input or
upstream_rejected
([#2402](#2402))
([749770b](749770b))
* **search:** load each Generation's schema graph once per search
([#2448](#2448))
([445d945](445d945))
* **search:** retry a failed Saved Function only after one interval
([#2460](#2460))
([a61ab3a](a61ab3a))
* **search:** return no hits for a query without a letter or digit
([#2561](#2561))
([bb0a4f0](bb0a4f0))
* **search:** start the write limit at the lock and build rows before
the write ([#2575](#2575))
([06ad55d](06ad55d))
* **search:** stop a self-referential Promise result from overflowing
the stack ([#2543](#2543))
([1d4f257](1d4f257))
* **search:** stop retrying an index write that fails the same way every
time ([#2548](#2548))
([e3b6d15](e3b6d15))


### Performance Improvements

* **catalog:** dedup credential destinations once per build, not per
Operation ([#2555](#2555))
([0afbcf5](0afbcf5))
* **catalog:** project each named TypeScript type once per Provider
([#2443](#2443))
([153c273](153c273))
* **search:** drop schema text from the phrase test
([#2559](#2559))
([cfdbafa](cfdbafa))
* **search:** index each word of schema text once
([#2547](#2547))
([d1123fb](d1123fb))
* **search:** prepare search entries in the indexer after commit
([#2467](#2467))
([1ab6765](1ab6765))
* **search:** recount only Workspaces whose rows changed
([#2457](#2457))
([777cfb3](777cfb3))
* **search:** skip unchanged rows when an index write runs again
([#2459](#2459))
([43b5188](43b5188))
* **search:** write only the statistics rows that changed
([#2458](#2458))
([8e2832c](8e2832c))

---
This PR was generated with [Release
Please](https://github.com/googleapis/release-please). See
[documentation](https://github.com/googleapis/release-please#release-please).

---------

Co-authored-by: coral-release-bot[bot] <269256696+coral-release-bot[bot]@users.noreply.github.com>
Co-authored-by: release-please[bot] <release-please[bot]@users.noreply.github.com>
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