Operating System
Linux (WSL2)
Run Mode
Docker
App Version
0.13.0 (branch v0.14.0rc)
Bug Description
API keys entered in the Settings UI are saved only to browser localStorage via Zustand store, but never persisted to the server's credentials.json. This causes authentication failures when agents run because the server reads credentials from credentials.json, not localStorage.
Additionally, the Docker nginx configuration is missing an /api proxy rule, causing all API requests to return the SPA HTML instead of being proxied to the backend server.
Root Cause Analysis
Issue 1: Write path mismatch
In apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts, the handleSave() function only updates the Zustand store:
const handleSave = async () => {
const keys = { anthropic: anthropicKey, google: googleKey, openai: openaiKey };
setApiKeys(keys); // Only saves to Zustand/localStorage
// Missing: api.settings.updateCredentials({ apiKeys: keys })
};
Issue 2: Read path mismatch
The hook initializes from useAppStore().apiKeys which is empty after page reload because apiKeys is intentionally excluded from localStorage persistence for security. The hook never fetches credentials from the server on mount.
Issue 3: Docker nginx missing API proxy
In apps/ui/nginx.conf:
location / {
try_files $uri $uri/ /index.html; # All requests fall through to SPA
}
# Missing: location /api/ { proxy_pass http://server:3008; }
Issue 4: Setup wizard also affected
apps/server/src/routes/setup/routes/store-api-key.ts writes to .env and process.env but not to credentials.json.
Steps to Reproduce
- Start automaker in Docker mode (
docker compose up)
- Open http://localhost:3007
- Go to Settings > API Keys
- Enter an Anthropic API key and click Save
- Run
docker exec automaker-server cat /data/credentials.json - file is empty or missing apiKeys
- Try to run an agent - fails with "Claude Code process exited with code 1"
- Refresh the settings page - API key field is empty
Expected Behavior
- API keys saved in Settings UI should persist to
credentials.json on the server
- On page reload, saved keys should be fetched from the server (masked for security)
- Agent execution should use credentials from
credentials.json
- Docker nginx should proxy
/api/* requests to the backend
Actual Behavior
- Keys only saved to browser localStorage
- Keys lost on page reload (localStorage cleared or different browser)
- Agent authentication fails because server has no credentials
- In Docker mode, API requests return HTML instead of proxying to backend
Suggested Fix
use-api-key-management.ts: Call api.settings.updateCredentials() in handleSave()
use-api-key-management.ts: Fetch masked credentials from server on mount via api.settings.getCredentials()
store-api-key.ts: Accept SettingsService and write to credentials.json
apps/server/src/routes/setup/index.ts: Pass settingsService to createStoreApiKeyHandler()
nginx.conf: Add /api location block with proxy_pass to server:3008
Related Issues
Screenshots
N/A
Relevant Logs
ERROR [ClaudeProvider] executeQuery() error during execution: {
type: 'execution',
message: 'Claude Code process exited with code 1',
...
}
Browser console when fetching credentials through nginx without proxy:
fetch('/api/settings/credentials', {method: 'GET', credentials: 'include'})
Uncaught (in promise) SyntaxError: Unexpected token '<', "<!doctype "... is not valid JSON
Additional Context
The security notice in the UI incorrectly states "API keys are stored in your browser's local storage" - the intended design appears to be server-side storage in credentials.json, but the write path was never implemented.
Checklist
Operating System
Linux (WSL2)
Run Mode
Docker
App Version
0.13.0 (branch v0.14.0rc)
Bug Description
API keys entered in the Settings UI are saved only to browser localStorage via Zustand store, but never persisted to the server's
credentials.json. This causes authentication failures when agents run because the server reads credentials fromcredentials.json, not localStorage.Additionally, the Docker nginx configuration is missing an
/apiproxy rule, causing all API requests to return the SPA HTML instead of being proxied to the backend server.Root Cause Analysis
Issue 1: Write path mismatch
In
apps/ui/src/components/views/settings-view/api-keys/hooks/use-api-key-management.ts, thehandleSave()function only updates the Zustand store:Issue 2: Read path mismatch
The hook initializes from
useAppStore().apiKeyswhich is empty after page reload becauseapiKeysis intentionally excluded from localStorage persistence for security. The hook never fetches credentials from the server on mount.Issue 3: Docker nginx missing API proxy
In
apps/ui/nginx.conf:Issue 4: Setup wizard also affected
apps/server/src/routes/setup/routes/store-api-key.tswrites to.envandprocess.envbut not tocredentials.json.Steps to Reproduce
docker compose up)docker exec automaker-server cat /data/credentials.json- file is empty or missing apiKeysExpected Behavior
credentials.jsonon the servercredentials.json/api/*requests to the backendActual Behavior
Suggested Fix
use-api-key-management.ts: Callapi.settings.updateCredentials()inhandleSave()use-api-key-management.ts: Fetch masked credentials from server on mount viaapi.settings.getCredentials()store-api-key.ts: AcceptSettingsServiceand write tocredentials.jsonapps/server/src/routes/setup/index.ts: PasssettingsServicetocreateStoreApiKeyHandler()nginx.conf: Add/apilocation block with proxy_pass to server:3008Related Issues
Screenshots
N/A
Relevant Logs
Browser console when fetching credentials through nginx without proxy:
Additional Context
The security notice in the UI incorrectly states "API keys are stored in your browser's local storage" - the intended design appears to be server-side storage in
credentials.json, but the write path was never implemented.Checklist