Skip to content

In-memory credential cache not cleared on re-login — stale credentials persist in long-running processes #69

Description

@chenliuyun

Problem

When a user re-authenticates (switches accounts) via switchbot config set-token or switchbot auth keychain set, the in-memory credential cache is not invalidated. Long-running processes — most critically the MCP server — continue to use the old credentials indefinitely.

Root cause

Two independent in-memory caches lack production invalidation paths:

1. Credential priming cache (src/credentials/prime.ts)

let cache: CacheEntry | null = null;

export async function primeCredentials(profile: string): Promise<void> {
  if (cache?.profile === profile) return;  // short-circuits — never re-fetches
  ...
}
  • Populated once at CLI startup via preAction hook (src/index.ts:133).
  • loadConfig() and tryLoadConfig() both check getPrimedCredentials() before falling back to disk/keychain (src/config.ts:78-79, 129-130).
  • __resetPrimedCredentials() exists but is only used in tests.

2. Device list cache (src/devices/cache.ts)

const _listCacheByProfile = new Map<string, DeviceCache | null>();

export function loadCache(): DeviceCache | null {
  const key = cacheKey();
  if (_listCacheByProfile.has(key)) return _listCacheByProfile.get(key)!;  // in-memory hit, never re-reads disk
  ...
}
  • resetListCache() / resetStatusCache() exist but are only used in tests.

3. saveConfig() clears nothing

src/config.ts:saveConfig() writes new credentials to disk but does not clear the credential priming cache or the device caches.

Steps to reproduce

  1. Start the MCP server with account A credentials: switchbot mcp serve
  2. Switch to account B: switchbot config set-token <token-b> <secret-b>
  3. Call any MCP tool that hits the API (e.g. list_devices)
  4. The server still uses account A credentials — the primeCredentials cache was never cleared

Affected components

Cache File Storage Invalidation
Credentials src/credentials/prime.ts In-memory (process) None (test-only helper)
Device list src/devices/cache.ts In-memory + disk Disk only (cache clear); in-memory persists
Device status src/devices/cache.ts In-memory + disk Disk only (cache clear); in-memory persists

Suggested fix

  1. Call __resetPrimedCredentials() (or export it under a meaningful name) from saveConfig() so writing new credentials clears the cache.
  2. In the MCP server HTTP path, call primeCredentials() per-request inside withRequestContext() so profile-switched requests always pick up the latest credentials.
  3. Similarly clear the device list/status in-memory caches on credential rotation.

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions