Fix frontend settings API configuration - #33
Conversation
Co-authored-by: up2itnow0822 <up2itnow0822@gmail.com>
| const handleSave = () => { | ||
| persistBackendUrl(backendUrl); | ||
| saveApiBaseUrl(backendUrl); | ||
| setSessionAuthToken(apiKeyInputRef.current?.value || ''); |
There was a problem hiding this comment.
Auth token silently cleared on every settings save without a new token
setSessionAuthToken(apiKeyInputRef.current?.value || '') is called unconditionally, but the token input is always reset to blank when the modal opens (line 20). So any subsequent save — e.g., a user who only wants to update the backend URL — calls setSessionAuthToken(''), which sets sessionAuthToken = null and removes the in-memory auth credential. All subsequent protected API calls (executionsAPI, builderAPI, etc.) will then be sent without an Authorization header. The token should only be updated when the user actually types a new value into the field.
The same issue is present in frontend/src/app/settings/page.tsx at the equivalent handleSave.
| const handleSave = () => { | ||
| persistBackendUrl(backendUrl); | ||
| saveApiBaseUrl(backendUrl); | ||
| setSessionAuthToken(apiKeyInputRef.current?.value || ''); | ||
| alert('Settings saved. API keys are kept in memory only.'); |
There was a problem hiding this comment.
Same unconditional
setSessionAuthToken call here clears the in-memory auth token whenever the user saves any setting change without re-entering their token. Since the field always starts blank, any URL-only update wipes the credential.
| const handleSave = () => { | |
| persistBackendUrl(backendUrl); | |
| saveApiBaseUrl(backendUrl); | |
| setSessionAuthToken(apiKeyInputRef.current?.value || ''); | |
| alert('Settings saved. API keys are kept in memory only.'); | |
| const handleSave = () => { | |
| saveApiBaseUrl(backendUrl); | |
| const tokenValue = apiKeyInputRef.current?.value || ''; | |
| if (tokenValue) setSessionAuthToken(tokenValue); | |
| alert('Settings saved. API keys are kept in memory only.'); |


Bug and impact
The frontend settings UI saved backend URLs under keys the shared API client never read (
backend_base_url/agentnexus_backend_urlvsapi_url). Auth tokens entered in settings were also never connected to the API client after recent localStorage hardening. Users could save settings successfully but subsequent API requests still used the old backend URL and omitted Authorization headers, breaking protected flows such as executions and builder generation.A second critical frontend blocker was found during validation: the resolved viem version did not export
sendCallsSync/sendTransactionSyncrequired by wagmi, causing the app build/dev UI to fail before rendering.Root cause
Settings state and API request configuration diverged across three separate localStorage keys, and the token field became write-only when persistent token storage was removed. The modal also rendered inside the sticky/backdrop-filter navbar, which clipped fixed-position modal content in the browser.
Fix
document.bodyand added scroll-safe sizing so all fields remain reachable.^2.52.0and aligned its override so wagmi imports resolve during build/dev.Validation
pnpm --filter @agentnexus/frontend test -- --runTestsByPath src/lib/apiSettings.test.ts src/components/layout/SettingsModal.test.tsx✅pnpm --filter @agentnexus/frontend type-check✅pnpm --filter @agentnexus/frontend build✅python3 -m pytest✅Known unrelated repo-wide gate failures observed:
pnpm --filter @agentnexus/frontend teststill lets Jest collect Playwright e2e specs and fails on missingTransformStream; ruff/bandit/mdformat fail on pre-existing Python/docs issues outside this frontend fix.Greptile Summary
This PR fixes a settings/API configuration split where three different localStorage keys were used across the settings modal, settings page, and Axios client — causing saved URLs and auth tokens to be silently ignored on actual requests. It introduces a shared
apiSettings.tshelper that consolidates URL storage under a singleapi_urlkey with legacy key migration, stores auth tokens in memory only, and wires both settings surfaces and the Axios interceptors to this helper. The modal is also portaled todocument.bodyto escape navbar clipping, andviemis bumped to^2.52.0to fix a missing export needed by wagmi.apiSettings.tsreads fromapi_url, migratesbackend_base_url/agentnexus_backend_urlon first access, and removes the stale keys — ensuring the Axios interceptor'sgetApiBaseUrl()call always sees the user-configured URL without a page reload.setSessionAuthToken/getSessionAuthTokenreplace direct localStorage reads in the Axios auth interceptor, but bothhandleSavehandlers callsetSessionAuthToken(input?.value || '')unconditionally — so saving settings with a blank token field (the default every time the modal reopens) silently clears any previously-set in-memory token and breaks protected API calls until the token is re-entered.Confidence Score: 3/5
The URL consolidation and legacy migration are solid, but both save handlers unconditionally overwrite the in-memory auth token with an empty value whenever the user saves settings without retyping their credential — this breaks protected API flows silently on every subsequent save.
The core settings-key fix is correct and the Axios interceptor wiring works. However, the unconditional
setSessionAuthToken(input?.value || '')call in bothSettingsModal.handleSaveandsettings/page.handleSavemeans that after a user sets a token and later reopens settings to adjust only the URL, clicking Save clears the credential they already entered. Protected endpoints (/executions,/builder/generate, etc.) will receive noAuthorizationheader until the token is re-entered, which is a silent regression on exactly the protected flows this PR was meant to fix.frontend/src/components/layout/SettingsModal.tsxandfrontend/src/app/settings/page.tsx— both need thesetSessionAuthTokencall guarded so it only fires when the token field is non-empty.Important Files Changed
hasBrowserStorage()is properly applied throughout.setSessionAuthTokenis called unconditionally with a blank value on every save, silently clearing the in-memory auth token whenever the user saves without re-entering their credential.apiSettingshelpers; per-request interceptor overridesbaseURLso no page reload is needed, and the removal of the localStorage auth-token read is correct.^2.52.0to satisfy wagmi'ssendCallsSync/sendTransactionSyncexports;@types/jestadded as a dev dependency; override aligned to exact2.52.0.Sequence Diagram
sequenceDiagram participant UI as Settings Modal / Page participant AS as apiSettings.ts participant LS as localStorage participant AX as Axios interceptor participant BE as Backend API UI->>AS: saveApiBaseUrl(url) AS->>LS: setItem('api_url', url) AS->>LS: removeItem('backend_base_url') AS->>LS: removeItem('agentnexus_backend_url') UI->>AS: setSessionAuthToken(token or '') Note over AS: sessionAuthToken = token (in-memory)<br/>⚠️ empty string → sets null, clears token AS->>LS: removeItem('auth_token') AX->>AS: getApiBaseUrl() AS->>LS: getItem('api_url') AS-->>AX: resolved URL AX->>AS: getSessionAuthToken() AS-->>AX: sessionAuthToken (or null) AX->>BE: request with baseURL + optional Authorization headerComments Outside Diff (1)
frontend/src/components/layout/SettingsModal.test.tsx, line 82-101 (link)The only test that exercises
handleSaveenters a token before clicking save. There is no test for: (1) set a token, (2) reopen the modal, (3) save with a blank token field — which is the exact flow that currently clears the in-memory token unexpectedly. Adding that case would have caught the conditional-update gap flagged above.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
Reviews (1): Last reviewed commit: "fix: restore frontend settings API confi..." | Re-trigger Greptile