Skip to content

fix(auth): bound store-time /auth/me validation so a slow backend defers instead of bouncing sign-in (#5166) - #5336

Merged
senamakel merged 2 commits into
tinyhumansai:mainfrom
YellowSnnowmann:fix/auth-me-store-timeout-5166
Aug 3, 2026
Merged

fix(auth): bound store-time /auth/me validation so a slow backend defers instead of bouncing sign-in (#5166)#5336
senamakel merged 2 commits into
tinyhumansai:mainfrom
YellowSnnowmann:fix/auth-me-store-timeout-5166

Conversation

@YellowSnnowmann

@YellowSnnowmann YellowSnnowmann commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Bound the store-time GET /auth/me sign-in validation to a 12s budget (was the shared backend client's 120s request ceiling), well under the desktop sign-in RPC timeout.
  • On budget exhaustion, return a transient-classified timeout so a live-exp JWT routes into the existing caller-authorized deferred-validation path instead of hanging.
  • Net effect: a reachable-but-slow backend no longer bounces a genuinely-authenticated user back to sign-in — they land in the app with deferred revalidation.
  • Budget is overridable via OPENHUMAN_AUTH_ME_STORE_TIMEOUT_MS (documented in .env.example).

Problem

Sentry TAURI-REACT-1VError: auth store failed: auth_me_timeout (26 events, 4 users, production).

Tracing the invariant "a valid, OAuth-succeeded session must not bounce back to sign-in" backward:

  • Store-time GET /auth/me validation in fetch_current_user_for_session_store (src/openhuman/security/credentials/ops.rs) runs on the shared BackendOAuthClient's 120s request timeout (src/api/rest.rs:279-280).
  • The desktop sign-in RPC that drives auth_store_session gives up far sooner — AUTH_STORE_TIMEOUT_MS (25s) × AUTH_STORE_RETRIES (2) in app/src/utils/desktopDeepLinkListener.ts.
  • So a reachable-but-slow backend lets /auth/me hang past the frontend's patience: the RPC times out and bounces the user before the existing allowPendingBackendValidation deferred-validation fallback (ops.rs, which persists a live-exp JWT for later revalidation) ever gets a chance to fire.

PR #5171 already downgraded the Sentry level to warning for transient kinds — that reduced noise but did not close the user-facing bounce, because the fast-fail-into-deferred path still couldn't trigger under a slow backend.

Solution

  • Wrap the store-time /auth/me call in tokio::time::timeout(auth_me_store_validation_budget()); the prior body becomes fetch_current_user_for_session_store_inner.
  • On elapse, return "GET /auth/me validation timeout after {ms}ms (store-time budget exceeded)" — worded to contain a TRANSIENT_TRANSPORT_PHRASES phrase ("timeout") so the existing auth_me_store_failure_is_transient classifier buckets it as transient and store_session_inner routes a live-exp JWT into the deferred-validation branch.
  • Default budget 12s (AUTH_ME_STORE_VALIDATION_BUDGET), comfortably under the frontend's 25s outer bound; overridable via OPENHUMAN_AUTH_ME_STORE_TIMEOUT_MS for ops tuning/tests. Invalid/non-positive overrides fall back to the default.
  • Logic lives in the Rust core (per repo convention); no frontend change needed — the 25s RPC bound stays correct and now covers the 12s inner budget with headroom.

Design note: the fallback still requires a locally-valid JWT (jwt_exp_live_at) and stores only { pendingBackendValidation: true } — it does not copy identity claims from an unverified token, so this does not weaken the auth contract. A genuine 401/non-transient failure is unaffected and still hard-fails to sign-in.

Submission Checklist

  • Tests added or updated (happy path + at least one failure / edge case) per Testing Strategy
  • Diff coverage ≥ 80% — new lines exercised by the two new tests (pnpm test:rust locally); the timeout Err branch, budget resolver, and warn path are all covered
  • N/A — Coverage matrix: behaviour-only change to an existing sign-in path (no added/removed/renamed feature row)
  • All affected feature IDs from the matrix are listed under ## Related — N/A (behaviour-only)
  • No new external network dependencies introduced (tests use an in-process axum mock backend)
  • N/A — Manual smoke checklist: no release-cut surface changed (internal timeout bound + env var only)
  • Linked issue closed via Closes #5166 in ## Related

Impact

  • Desktop sign-in (all platforms). A slow-but-reachable backend now yields a successful pending-validation sign-in within ~12s instead of a ~50s bounce to the login page. No behaviour change on a healthy backend (healthy /auth/me responds well under 1s).
  • Security: unchanged — deferred fallback still gated on a live-exp JWT and never copies identity claims; non-transient (401) failures still hard-fail.
  • Migration/compat: none. New env var is optional with a safe default.

Related


AI Authored PR Metadata (required for Codex/Linear PRs)

Linear Issue

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

Commit & Branch

  • Branch: fix/auth-me-store-timeout-5166
  • Commit SHA: 87fd774

Validation Run

  • pnpm --filter openhuman-app format:check — N/A (no app/src changes)
  • pnpm typecheck — N/A (no TS changes)
  • Focused tests: cargo test --lib security::credentials::ops — 50 passed
  • Rust fmt/check (if changed): cargo fmt --check clean, cargo clippy --lib clean
  • Tauri fmt/check (if changed): N/A (core crate only)

Validation Blocked

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

Behavior Changes

  • Intended behavior change: slow-backend store-time /auth/me fails fast into deferred validation instead of hanging until the sign-in RPC bounces the user.
  • User-visible effect: sign-in succeeds (pending revalidation) under a slow backend rather than returning to the login page.

Parity Contract

  • Legacy behavior preserved: healthy backend, 401/non-transient failures, and non-live-exp tokens behave exactly as before.
  • Guard/fallback/dispatch parity checks: auth_me_store_failure_is_transient classification and the jwt_exp_live_at gate are unchanged; only the trigger (timeout vs. upstream error) is new.

Duplicate / Superseded PR Handling

Summary by CodeRabbit

  • New Features

    • Added a configurable 12-second timeout for sign-in session validation.
    • Added support for customizing the timeout through OPENHUMAN_AUTH_ME_STORE_TIMEOUT_MS.
    • Slow validation services now defer eligible live-session checks rather than blocking sign-in.
  • Bug Fixes

    • Preserved valid sessions when authentication validation times out.
    • Prevented unverified identity information from being reused after validation timeouts.
  • Documentation

    • Added the new timeout setting and its default value to the example configuration.

…ers instead of bouncing sign-in (tinyhumansai#5166)

The store-time GET /auth/me validation ran on the shared backend client's
120s request timeout, but the desktop sign-in RPC that drives
auth_store_session gives up after 25s x 2 retries. A reachable-but-slow
backend therefore let /auth/me hang past the frontend's patience: the RPC
timed out and bounced a genuinely-authenticated user back to sign-in
*before* the existing deferred-validation fallback could fire — the
auth_me_timeout error in Sentry TAURI-REACT-1V.

Cap store-time validation at a 12s budget (overridable via
OPENHUMAN_AUTH_ME_STORE_TIMEOUT_MS), well under the frontend budget, and
return a transient-classified timeout on exhaustion so a live-exp JWT
routes into the caller-authorized pending-session path. The user lands in
the app with deferred revalidation instead of being bounced.
@coderabbitai

coderabbitai Bot commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

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: ac332216-5a91-4b2b-83f5-35ed2a070852

📥 Commits

Reviewing files that changed from the base of the PR and between 87fd774 and 477106f.

📒 Files selected for processing (1)
  • src/openhuman/security/credentials/ops_tests.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/openhuman/security/credentials/ops_tests.rs

📝 Walkthrough

Walkthrough

The auth credential flow adds a configurable 12-second /auth/me validation budget. Timed-out validation returns a transient error, enabling deferred validation while preserving the session without storing unverified identity claims. Tests cover timeout behavior and environment overrides.

Changes

Auth validation timeout

Layer / File(s) Summary
Configurable /auth/me validation timeout
.env.example, src/openhuman/security/credentials/ops.rs
Adds the 12-second default, the OPENHUMAN_AUTH_ME_STORE_TIMEOUT_MS override, and timeout handling around session-user validation and retries.
Timeout and override validation tests
src/openhuman/security/credentials/ops_tests.rs
Adds a hanging /auth/me backend and tests deferred validation, session preservation, claim protection, and valid, zero, and invalid overrides.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant SessionStore
  participant CredentialOperations
  participant AuthMeBackend
  SessionStore->>CredentialOperations: Validate session user
  CredentialOperations->>AuthMeBackend: Request /auth/me
  AuthMeBackend-->>CredentialOperations: Response or timeout
  CredentialOperations-->>SessionStore: Identity or deferred validation
Loading

Suggested labels: rust-core

Poem

A rabbit checks the sign-in gate,
Twelve seconds sets the waiting rate.
If /auth/me goes slow,
Deferred checks can flow.
No guessed claims cross the plate.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main change: bounding store-time /auth/me validation so slow backends defer instead of failing sign-in.
Linked Issues check ✅ Passed The changes address issue #5166 by deferring validation after a transient /auth/me timeout while preserving hard failures for non-transient errors.
Out of Scope Changes check ✅ Passed The environment example, timeout implementation, and focused tests all support the linked issue and stated objectives.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

@YellowSnnowmann
YellowSnnowmann marked this pull request as ready for review August 3, 2026 12:08
@YellowSnnowmann
YellowSnnowmann requested a review from a team August 3, 2026 12:08
@coderabbitai coderabbitai Bot added the rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure. label Aug 3, 2026

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/openhuman/security/credentials/ops_tests.rs`:
- Around line 376-386: In the timeout assertion for
store_session_with_deferred_validation, replace the 10-second upper bound with
one safely above the configured 200ms budget but below the default 12-second
budget, so multi-second regressions fail while allowing normal timing variance.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bdd7676f-6386-40e6-a4b3-89110a4a440c

📥 Commits

Reviewing files that changed from the base of the PR and between b668251 and 87fd774.

📒 Files selected for processing (3)
  • .env.example
  • src/openhuman/security/credentials/ops.rs
  • src/openhuman/security/credentials/ops_tests.rs

Comment thread src/openhuman/security/credentials/ops_tests.rs
@greptile-apps

greptile-apps Bot commented Aug 3, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes a user-visible sign-in bounce (Sentry TAURI-REACT-1V) where a reachable-but-slow backend caused the store-time GET /auth/me validation to hang past the desktop sign-in RPC timeout. The fix wraps the validation in a tokio::time::timeout with a 12 s default budget (overridable via OPENHUMAN_AUTH_ME_STORE_TIMEOUT_MS), and on expiry emits a "timeout"-keyed transient error that routes live-exp JWTs into the existing deferred-validation fallback instead of bouncing the user.

  • ops.rs: fetch_current_user_for_session_store now wraps the renamed ..._inner function with a configurable tokio::time::timeout; budget is read from an env var with positive-integer validation and a hard-coded 12 s default.
  • ops_tests.rs: two new tests added — a #[tokio::test] that drives a 60 s hanging mock backend with a 200 ms test budget and asserts deferred-session state, and a sync unit test that covers all three env-var branches of the budget resolver.
  • .env.example: new commented OPENHUMAN_AUTH_ME_STORE_TIMEOUT_MS entry documents the override for ops use.

Confidence Score: 5/5

Safe to merge — the change is a targeted timeout wrapper around a single async call with no mutations to the auth contract, identity claims, or non-transient failure paths.

The new tokio::time::timeout wraps only the store-time /auth/me call; all existing branches (healthy backend, 401, non-transient errors, expired JWTs) are structurally unchanged and covered by existing tests. The two new tests exercise the added paths end-to-end with an in-process mock. The env-var override is narrowly scoped with a safe fallback. No auth contract change was introduced.

Files Needing Attention: No files require special attention.

Important Files Changed

Filename Overview
src/openhuman/security/credentials/ops.rs Adds AUTH_ME_STORE_VALIDATION_BUDGET constant and auth_me_store_validation_budget() resolver, wraps the store-time /auth/me call in tokio::time::timeout, renames original body to _inner. Transient error message correctly contains 'timeout' to satisfy the existing auth_me_store_failure_is_transient classifier. No correctness issues found.
src/openhuman/security/credentials/ops_tests.rs Adds EnvVarGuard::set, spawn_auth_me_hang, and two new tests exercising the timeout path and the budget-resolver env-var branches. Timing assertion has 10x headroom (200 ms budget vs 2 s wall-clock bound), which is reasonable for CI.
.env.example Adds commented documentation for OPENHUMAN_AUTH_ME_STORE_TIMEOUT_MS with the correct default (12000) and context. No issues.

Sequence Diagram

sequenceDiagram
    participant FE as Frontend (desktopDeepLinkListener)
    participant RPC as store_session_inner
    participant T as tokio::time::timeout (12 s budget)
    participant Inner as fetch_current_user_inner
    participant BE as Backend GET /auth/me

    FE->>RPC: auth_store_session (25 s RPC timeout)
    RPC->>T: start 12 s budget
    T->>Inner: call
    Inner->>BE: GET /auth/me (first attempt)

    alt "Backend healthy (< 12 s)"
        BE-->>Inner: 200 OK + user JSON
        Inner-->>T: Ok(user)
        T-->>RPC: Ok(user)
        RPC-->>FE: session stored
    else "Backend slow (> 12 s) — NEW PATH"
        Note over T: 12 s elapsed
        T-->>RPC: Err(timeout)
        Note over RPC: auth_me_store_failure_is_transient = true, allow_pending_backend_validation = true, jwt_exp_live_at = Some(exp)
        RPC-->>FE: session stored (pendingBackendValidation: true)
    else Non-transient failure (401)
        BE-->>Inner: 401 Unauthorized
        Inner-->>T: Err(401)
        T-->>RPC: Err(401)
        Note over RPC: not transient, hard fail
        RPC-->>FE: Err (user bounces to sign-in)
    end
Loading

Reviews (2): Last reviewed commit: "test(auth): tighten store-time budget as..." | Re-trigger Greptile

…5166)

CodeRabbit: the <10s upper bound let a multi-second timeout regression pass.
With a 200ms configured budget and 12s default, bound at <2s so a regression
fails while allowing normal timing variance.
@senamakel
senamakel merged commit 45328dc into tinyhumansai:main Aug 3, 2026
24 of 25 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rust-core Core Rust runtime in src/: CLI, core_server, shared infrastructure.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Error: auth store failed: auth_me_timeout — frontend auth check timing out

2 participants