Skip to content

[BUG] OAuth disk persistence does not survive Docker container restarts #837

Description

@julienld

Related

Follow-up to #787 / #790. The disk persistence fix in #790 writes to ~/.ha-mcp/oauth_state.json inside the container filesystem, which is ephemeral by default. Container restarts still lose all OAuth state.

Root Cause

HomeAssistantOAuthProvider defaults state_dir to Path.home() / ".ha-mcp" (i.e. /root/.ha-mcp in Docker). No VOLUME is declared in the Dockerfile, and __main__.py does not pass a state_dir to the constructor. The HA add-on has the same issue unless /root/.ha-mcp happens to be on a persistent volume managed by Supervisor.

Possible Fixes

Option A — Fully stateless tokens (recommended)
Make both access and refresh tokens stateless by encoding the HA LLAT in each (same base64 pattern already used for access tokens). Set long expiry aligned with the LLAT itself (10 years in HA). On refresh, decode the LLAT from the old refresh token and issue new tokens — no server-side map needed.

  • Access token: base64({"ha_token": "...", "iat": ..., "type": "access"}) — long expiry (e.g. 10 years)
  • Refresh token: base64({"ha_token": "...", "iat": ..., "type": "refresh"}) — long expiry
  • Eliminates _refresh_to_access_map, _save_state(), _load_state(), and all disk I/O
  • Survives container restarts by design — zero server-side state for token management
  • Compatible with ChatGPT (which requires refresh tokens and refreshes on every tool call regardless of expiry)
  • Security boundary unchanged: if the LLAT is revoked in HA, both token types fail immediately on the next API call

Clients still need to re-register (DCR) after container restart, but DCR is automatic and transparent.

Option B — Volume mount + state_dir configuration
Declare a VOLUME in Dockerfile and/or pass state_dir=/data for the HA add-on. Document volume mount for standalone Docker.

  • Pros: Minimal code change
  • Cons: Requires user to configure volume mount correctly; add-on needs to use Supervisor persistent storage path; doesn't eliminate the complexity of disk persistence code

Recommendation

Option A aligns with the existing stateless access token design and eliminates all server-side persistence. The LLAT is already 10 years in HA — the OAuth token expiry should match rather than impose an artificial 1-hour boundary that forces complex refresh state management.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions