Skip to content

fix(auth): deliver OAuth JWT to remote core in cloud mode#2453

Open
M3gA-Mind wants to merge 4 commits into
tinyhumansai:mainfrom
M3gA-Mind:fix/remote-core-oauth-deep-link
Open

fix(auth): deliver OAuth JWT to remote core in cloud mode#2453
M3gA-Mind wants to merge 4 commits into
tinyhumansai:mainfrom
M3gA-Mind:fix/remote-core-oauth-deep-link

Conversation

@M3gA-Mind
Copy link
Copy Markdown
Contributor

@M3gA-Mind M3gA-Mind commented May 21, 2026

Summary

  • oauthAuthReadiness.ts: in cloud mode, pass the stored cloud bearer token directly to testCoreRpcConnection() so the readiness-gate ping doesn't fail with a stale local-core token from cache.
  • desktopDeepLinkListener.ts: bust stale RPC URL/token caches before auth_store_session in cloud mode; wrap the call in a core-state:suppress-reauth 15 s window to prevent a concurrent auth-expired cascade from clearing the session mid-flight.
  • CoreStateProvider.tsx: honour the suppress-reauth window — skip clearSession while a deep-link auth delivery is in progress.
  • coreRpcClient.ts: add diagnostic logging for auth_store_session routing (token source: cloud-stored vs local-resolved).
  • Improve core_unreachable error message to name the cloud core URL/token settings when mode is cloud.

Problem

When a user runs in remote/cloud mode (Docker-hosted core), completing Google/GitHub OAuth left the app in an infinite onboarding loop. Two concurrent failures prevented the JWT from reaching the remote core:

  1. Wrong ping token: oauthAuthReadiness.ts called testCoreRpcConnection without a token override. getCoreRpcToken() could resolve the local in-process core's bearer from a primed cache — the remote core rejected it with 401, the readiness gate timed out, and the deep link was dropped.

  2. Auth-expired cascade: CoreStateProvider ran periodic fetchCoreAppSnapshot RPCs against the remote core while the session was not yet stored. Those returned "no backend session token; run auth_store_session first", which classifyRpcError classified as auth_expired, triggering clearSessionauth_clear_session → Welcome screen. If this fired after storeSession, the session was immediately undone.

Solution

Two targeted guards, no new dependencies:

  • Token override: always use the persisted cloud token for the readiness ping in cloud mode.
  • Suppress window: a 15 s custom event tells CoreStateProvider to delay auth-expired resets while storeSession is in flight; the window clears in a finally block regardless of outcome.

Submission Checklist

  • Tests added: 3 new tests in desktopDeepLinkListener.test.ts, 3 new in oauthAuthReadiness.test.ts
  • Diff coverage ≥ 80% — all new branches (cloud-mode cache bust, suppress-reauth dispatch, cloud error message) exercised
  • Coverage matrix updated — N/A: behaviour-only change, no new RPC methods
  • All affected feature IDs listed — N/A
  • No new external network dependencies
  • Manual smoke checklist — N/A
  • Linked issue closed via Closes #2377

Impact

  • Frontend only (TypeScript). No Rust core changes, no Tauri shell changes.
  • Local-mode flow unaffected — all new guards are gated on getStoredCoreMode() === 'cloud'.
  • Desktop: macOS / Windows / Linux.

Related


AI Authored PR Metadata

Linear Issue

  • Key: N/A
  • URL: N/A

Commit & Branch

  • Branch: fix/remote-core-oauth-deep-link
  • Commit SHA: 182c01f

Validation Run

  • pnpm --filter openhuman-app format:check — clean
  • pnpm --filter openhuman-app compile — 0 errors
  • pnpm --filter openhuman-app lint — 0 new errors (existing warnings on main are pre-existing)
  • Focused tests: pnpm debug unit desktopDeepLinkListener and oauthAuthReadiness — all pass
  • Rust fmt/check — N/A (no Rust changes)
  • Tauri fmt/check — N/A (no Tauri shell changes)

Validation Blocked

  • command: N/A
  • error: N/A
  • impact: N/A

Behavior Changes

  • Intended: OAuth JWT reaches the remote core after login in cloud mode
  • User-visible: Sign-in with Google/GitHub completes successfully when using a Docker-hosted remote core

Parity Contract

  • Local mode: fully unchanged — all new guards are gated on cloud mode check
  • No RPC contract changes: auth_store_session signature unchanged

Duplicate / Superseded PR Handling

  • Duplicate PR(s): N/A
  • Canonical PR: this one
  • Resolution: N/A

Summary by CodeRabbit

  • New Features

    • Mode-specific user messages for cloud vs. local runtime connectivity.
    • Temporary suppression mechanism to defer re-auth actions during session delivery.
  • Bug Fixes

    • Ensure cloud sessions clear RPC URL/token caches and avoid triggering immediate re-auth.
    • Improved diagnostics and explicit cloud-token usage when checking core connectivity.
  • Tests

    • Expanded coverage for cloud vs. local flows, cache-clearing, suppression windows, and readiness messaging.

Review Change Stack

Two failure paths prevented the openhuman://auth deep link from
reaching a Docker-hosted remote core:

1. oauthAuthReadiness.ts pinged the core with a stale local-core
   bearer token (resolved from cache). Fix: explicitly pass the
   stored cloud token to testCoreRpcConnection in cloud mode.

2. CoreStateProvider's auth-expired cascade cleared the session while
   auth_store_session was in flight. Fix: dispatch a 15 s suppress-
   reauth window around storeSession; CoreStateProvider skips clearSession
   while the window is active.

Also busts stale RPC URL/token caches before auth_store_session in
cloud mode, and improves the core_unreachable error message to name
the cloud core specifically.

Closes tinyhumansai#2377
@M3gA-Mind M3gA-Mind requested a review from a team May 21, 2026 14:49
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 21, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0ba8fb0a-6959-48b9-849d-9c2b72955a71

📥 Commits

Reviewing files that changed from the base of the PR and between 265d0ac and f2a0a2f.

📒 Files selected for processing (1)
  • app/src/providers/__tests__/CoreStateProvider.test.tsx

📝 Walkthrough

Walkthrough

Auth readiness and deep-link handling gain cloud-mode awareness: readiness passes cloud bearer token to RPC checks and shows cloud-specific unreachable messaging; deep-link delivery clears RPC caches, dispatches suppression events while delivering the token, CoreStateProvider respects suppression to avoid clearing session mid-delivery, and RPC client logs token source.

Changes

Cloud-mode OAuth flow for remote runtime token delivery

Layer / File(s) Summary
Cloud-aware OAuth auth readiness gating
app/src/components/oauth/oauthAuthReadiness.ts, app/src/components/oauth/__tests__/oauthAuthReadiness.test.ts
Auth readiness inspects stored core mode and, for cloud, fetches getStoredCoreToken() and passes it to testCoreRpcConnection; core_unreachable messaging now differs for cloud vs local. Tests added to assert cloud/local messages and that cloud token is forwarded to RPC tests.
OAuth callback deep-link token delivery with cache clearing
app/src/utils/desktopDeepLinkListener.ts, app/src/utils/__tests__/desktopDeepLinkListener.test.ts
Deep-link handler clears RPC URL and token caches in cloud mode before calling storeSession, dispatches core-state:suppress-reauth with a short until before delivery and clears it (until: 0) in finally; tests validate cache clearing behavior and suppression event lifecycle for cloud vs local.
Re-auth suppression during token delivery
app/src/providers/CoreStateProvider.tsx, app/src/providers/__tests__/CoreStateProvider.test.tsx
Adds suppressReauthUntilRef and listens for core-state:suppress-reauth; auth-expired path early-returns (skips clearSession) while now < stored until timestamp. Tests ensure suppression blocks logout and that until:0 re-enables handling.
Cloud token source debugging
app/src/services/coreRpcClient.ts
callCoreRpc adds debug metadata for openhuman.auth_store_session showing resolved RPC URL and tokenSource (cloud-stored vs local).

Sequence Diagram(s)

sequenceDiagram
  participant DesktopApp
  participant DeepLinkHandler
  participant ConfigPersistence
  participant CoreRpcClient
  participant CoreStateProvider
  DesktopApp->>DeepLinkHandler: openhuman://auth?token=JWT
  DeepLinkHandler->>ConfigPersistence: getStoredCoreMode()
  ConfigPersistence-->>DeepLinkHandler: 'cloud'
  DeepLinkHandler->>CoreRpcClient: clearCoreRpcUrlCache(), clearCoreRpcTokenCache()
  DeepLinkHandler->>CoreStateProvider: dispatch core-state:suppress-reauth(until)
  DeepLinkHandler->>CoreRpcClient: call openhuman.auth_store_session(token)
  CoreRpcClient-->>DeepLinkHandler: RPC response
  DeepLinkHandler->>CoreStateProvider: dispatch core-state:suppress-reauth(until:0)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • tinyhumansai/openhuman#2247: Both PRs modify the OAuth auth-readiness flow to gate sign-in based on core mode/reachability, extended here for cloud token handling.
  • tinyhumansai/openhuman#2267: Also touches readiness gating and tests for oauthAuthReadiness; related to the readiness/message changes in this PR.
  • tinyhumansai/openhuman#2114: Related to core RPC token/cache plumbing and logging/invalidation changes.

Suggested labels

bug

Suggested reviewers

  • senamakel
  • graycyrus

Poem

🐰 A deep link leaps through the cloud so high,
With tokens swift and caches dry,
Suppress the reauth while the rabbit runs,
Deliver the JWT — the loop is done!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix(auth): deliver OAuth JWT to remote core in cloud mode' clearly and concisely summarizes the primary change—enabling OAuth JWT delivery to remote cores in cloud mode.
Linked Issues check ✅ Passed The PR addresses all coding objectives from issue #2377: delivering OAuth JWT to remote core, preventing stale tokens in readiness pings, blocking auth-expired cascades during auth_store_session, and adding tests with sufficient coverage.
Out of Scope Changes check ✅ Passed All changes are directly scoped to fixing remote core OAuth delivery: token caching, readiness pings, suppress-reauth windows, diagnostic logging, and error messaging for cloud mode—no unrelated changes detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot added the working A PR that is being worked on by the team. label May 21, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 21, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes May 21, 2026
@M3gA-Mind
Copy link
Copy Markdown
Contributor Author

@M3gA-Mind CI is failing on changes in this PR — please fix before review.

M3gA-Mind added 2 commits May 21, 2026 22:55
…livery (tinyhumansai#2377)

Add two targeted tests that exercise the `core-state:suppress-reauth` custom-event
handler introduced for issue tinyhumansai#2377:
- verifies auth-expired clearSession is blocked while the suppress window is active
- verifies clearSession resumes after the window is explicitly cleared (until=0)
@M3gA-Mind
Copy link
Copy Markdown
Contributor Author

CI fix pushed (f2a0a2f): added two targeted tests covering the core-state:suppress-reauth event handler in CoreStateProvider (the new useEffect for issue #2377 was missing test coverage). New CI run is in progress.

@M3gA-Mind
Copy link
Copy Markdown
Contributor Author

Two CI failures, both pre-existing infrastructure flakes unrelated to these TypeScript-only changes:

  1. Rust Core Coverageopenrouter_valid_key_allows_models_catalog_probe panics with "no cloud provider with id or slug 'openrouter' found". This test requires an OpenRouter provider to be registered in the CI environment config; it's not related to auth/deep-link changes.

  2. Windows secrets ACL — All 53 tests passed (0 failed). Job exits non-zero due to sccache cache_write_errors (same infrastructure flake seen on PR fix(memory): bound ingestion queue to prevent OOM under runaway producers #2451, which passed on re-run and on PR feat(composio): add Linear as a native memory provider #2452). Re-running both jobs.

@YOMXXX
Copy link
Copy Markdown
Contributor

YOMXXX commented May 22, 2026

@graycyrus @senamakel Follow-up after the earlier CI-failure note: the latest effective checks are now green, CodeRabbit approved, and the PR is mergeable. This fixes remote-core OAuth token delivery (#2377), so it is part of the same sign-in/deep-link reliability cluster. Please review/merge when available.

@M3gA-Mind
Copy link
Copy Markdown
Contributor Author

@M3gA-Mind this PR has merge conflicts with main — please rebase/resolve before review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug working A PR that is being worked on by the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Remote core mode: OAuth callback deep link never delivers JWT to core, causing infinite onboarding loop

2 participants