Skip to content

fix(desktop): use camelCase-aware parser for persisted native OAuth tokens (#73271) - #73437

Closed
JonthanaHanh wants to merge 1 commit into
NousResearch:mainfrom
JonthanaHanh:fix/native-oauth-token-rehydration
Closed

fix(desktop): use camelCase-aware parser for persisted native OAuth tokens (#73271)#73437
JonthanaHanh wants to merge 1 commit into
NousResearch:mainfrom
JonthanaHanh:fix/native-oauth-token-rehydration

Conversation

@JonthanaHanh

Copy link
Copy Markdown
Contributor

Summary

Desktop native OAuth sign-in works during the initial process lifetime, but after a cold restart the persisted token set cannot be rehydrated — the user is forced to re-authenticate.

Root cause: _loadNativeTokens() passes the decrypted persisted NativeTokenSet (camelCase: accessToken, refreshToken, expiresAt) through parseTokenResponse(), which expects raw gateway OAuth response format (snake_case: access_token, refresh_token, expires_at). The camelCase keys don't match, so the parser throws "Gateway token response missing access_token" and returns null — the stored tokens are silently discarded.

Changes

apps/desktop/electron/native-oauth.ts — Add rehydratePersistedTokens():

  • Accepts camelCase persisted shape (accessToken), falls back to snake_case (access_token) for belt-and-suspenders compatibility
  • Same validation as parseTokenResponse() (throws on missing access token)
  • Documented with docstring explaining why this is separate from parseTokenResponse()

apps/desktop/electron/main.ts — Use rehydratePersistedTokens() in _loadNativeTokens():

  • Line 6104: parseTokenResponse()rehydratePersistedTokens()
  • parseTokenResponse() is still used at line 6169 for raw gateway token exchange responses (correct usage)

apps/desktop/electron/native-oauth.test.ts — 4 new tests:

  • camelCase persisted token set round-trips correctly
  • Throws on missing accessToken
  • Falls back to snake_case keys (belt-and-suspenders)
  • Tolerates absent optional fields

Test Plan

  • Existing native-oauth tests pass
  • New rehydratePersistedTokens tests pass
  • Manual: sign in via native OAuth → close Desktop → reopen → should stay signed in without re-authentication prompt

Fixes #73271

…okens

Persisted NativeTokenSet uses camelCase keys (accessToken, refreshToken,
expiresAt, userId) while parseTokenResponse() expects snake_case from raw
gateway responses (access_token, refresh_token, expires_at, user_id).

When _loadNativeTokens() passes decrypted persisted JSON through
parseTokenResponse(), it always fails with "Gateway token response
missing access_token" because the camelCase keys don't match — forcing
the user to re-authenticate after every Desktop restart.

Add rehydratePersistedTokens() that accepts camelCase with snake_case
fallback, and use it in _loadNativeTokens() instead of parseTokenResponse().
Raw OAuth responses from the gateway still use parseTokenResponse().

Fixes NousResearch#73271
@alt-glitch alt-glitch added type/bug Something isn't working comp/desktop Electron desktop app (apps/desktop/*) area/auth Authentication, OAuth, credential pools P2 Medium — degraded but workaround exists sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data duplicate This issue or pull request already exists labels Jul 28, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Duplicate of #71524: both current diffs replace raw response parsing with a stored NativeTokenSet parser for _loadNativeTokens(). #71524 is the earlier focused repair and also retains load-error diagnostics.

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

Labels

area/auth Authentication, OAuth, credential pools comp/desktop Electron desktop app (apps/desktop/*) duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data sweeper:risk-session-state Sweeper risk: may lose/corrupt/mis-associate session or context state type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Desktop native OAuth tokens cannot rehydrate after restart — persisted token set is parsed as raw OAuth response

2 participants