mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
fix(auth): treat missing backend session token as auth-expired (#1504)
This commit is contained in:
@@ -500,6 +500,13 @@ describe('classifyRpcError', () => {
|
||||
['GET /teams failed (401 Unauthorized): {"success":false}', undefined, 'auth_expired'],
|
||||
['Session expired. Please log in again.', undefined, 'auth_expired'],
|
||||
['some prefix Session expired suffix', undefined, 'auth_expired'],
|
||||
[
|
||||
'composio unavailable: no backend session token. Sign in first (auth_store_session).',
|
||||
undefined,
|
||||
'auth_expired',
|
||||
],
|
||||
['no backend session token; run auth_store_session first', undefined, 'auth_expired'],
|
||||
['NO BACKEND SESSION TOKEN', undefined, 'auth_expired'],
|
||||
['HTTP 429 rate-limit exceeded', undefined, 'rate_limited'],
|
||||
['Budget exceeded for current period', undefined, 'budget_exceeded'],
|
||||
['Insufficient budget for request', undefined, 'budget_exceeded'],
|
||||
|
||||
@@ -77,6 +77,12 @@ export function classifyRpcError(message: string, httpStatus?: number): CoreRpcE
|
||||
if (httpStatus === 401) return 'auth_expired';
|
||||
if (httpStatus === 429) return 'rate_limited';
|
||||
if (/\(401\b.*Unauthorized\)|Session expired/i.test(message)) return 'auth_expired';
|
||||
// Core-side "no backend session token" → the auth profile is gone but the
|
||||
// frontend may still hold a stale sessionToken from an optimistic post-login
|
||||
// patch. Treat as auth-expired so `CoreStateProvider` clears the session and
|
||||
// `ProtectedRoute` bounces the user back to `/` (login) instead of trapping
|
||||
// them on an onboarding step that polls a failing RPC every 5 s.
|
||||
if (/no backend session token/i.test(message)) return 'auth_expired';
|
||||
if (/429.*rate.?limit/i.test(message)) return 'rate_limited';
|
||||
if (/Budget exceeded|Insufficient budget/i.test(message)) return 'budget_exceeded';
|
||||
if (/error sending request|client error \(Connect\)|timed out|ECONNREFUSED/i.test(message)) {
|
||||
|
||||
@@ -118,10 +118,20 @@ pub async fn invoke_method(state: AppState, method: &str, params: Value) -> Resu
|
||||
}
|
||||
|
||||
/// Helper to determine if an error message indicates an expired or invalid session.
|
||||
///
|
||||
/// "No backend session token" is also treated as a session-expired signal: the
|
||||
/// auth profile is missing entirely (the user was never signed in, or their
|
||||
/// stored profile was wiped between login and the next RPC). The frontend may
|
||||
/// still believe it holds a session token from an optimistic post-login patch,
|
||||
/// so we want the same auto-cleanup + UI-level re-auth path to fire instead of
|
||||
/// repeatedly reporting this as a hard error to Sentry. See #1465-ish: users
|
||||
/// stuck on the onboarding `SkillsStep` would spam `composio_list_connections`
|
||||
/// failures every 5 s without ever being bounced back to the login screen.
|
||||
fn is_session_expired_error(msg: &str) -> bool {
|
||||
let lower = msg.to_lowercase();
|
||||
(lower.contains("401") && lower.contains("unauthorized"))
|
||||
|| lower.contains("invalid token")
|
||||
|| lower.contains("no backend session token")
|
||||
|| msg.contains("SESSION_EXPIRED")
|
||||
}
|
||||
|
||||
|
||||
@@ -578,6 +578,25 @@ fn is_session_expired_error_does_not_match_unrelated_errors() {
|
||||
assert!(!is_session_expired_error(""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_session_expired_error_matches_missing_backend_session_token() {
|
||||
// Composio / web search / billing / team / webhooks / referral all surface
|
||||
// a "no backend session token" variant when the auth profile is gone. Each
|
||||
// of these should funnel into the auto-cleanup path instead of being
|
||||
// reported to Sentry as a fresh error on every 5 s poll.
|
||||
assert!(is_session_expired_error(
|
||||
"composio unavailable: no backend session token. Sign in first (auth_store_session)."
|
||||
));
|
||||
assert!(is_session_expired_error(
|
||||
"no backend session token; run auth_store_session first"
|
||||
));
|
||||
assert!(is_session_expired_error(
|
||||
"Web search unavailable: no backend session token. Sign in first so the server can proxy search."
|
||||
));
|
||||
// Case-insensitive match — the helper lowercases first.
|
||||
assert!(is_session_expired_error("NO BACKEND SESSION TOKEN"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn escape_html_escapes_all_special_chars() {
|
||||
let raw = r#"<script>alert("x&y'z")</script>"#;
|
||||
|
||||
Reference in New Issue
Block a user