Skip to content

Expose HA LLATs as individual NyxID services (blocked on NyxID #418) #1

@loning

Description

@loning

Summary

Users should be able to expose multiple HA long-lived access tokens (LLATs) through NyxID, each as its own service with its own HA user identity — for clean permission scoping between AI assistants / bots / read-only monitors.

Blocked on upstream: ChronoAIProject/NyxID#418 (server-side credential management for via-node services). Implement here once that lands.

Use case

A NyxID user running this add-on wants to proxy their HA with different permission scopes:

Purpose HA user LLAT scope Consumers
AI that edits Lovelace, manages integrations Admin account Full admin Claude / codex with high trust
Automation bot that only controls specific lights Scoped user (in HA, limited to area) Same as user Home automation scripts
Dashboard / monitoring view Read-only user Same Grafana, status pages, less-trusted AI

Today the add-on exposes exactly one Core identity (the add-on's non-admin service user via SUPERVISOR_TOKEN). Users cannot:

  • Route different callers to different HA identities through the same node
  • Provide an admin-level Core token without resorting to LAN + external node
  • Revoke a single consumer's access without touching all others

Desired UX (post-NyxID #418)

User creates N HA users in HA UI, generates an LLAT per user, then goes to NyxID web UI:

Add service:
  label:        "HA (Admin)"
  endpoint:     http://homeassistant.local:8123
  auth_method:  bearer
  via_node:     <this addon's node>
  credential:   <paste LLAT>   ← NyxID server stores, pushes to node via WS

Done. The add-on doesn't need to know anything about it. NyxID handles credential delivery. Adding / removing / rotating LLATs happens entirely in the NyxID web UI, no add-on restart required.

Why we're NOT implementing an ha_llats config field in the add-on today

It was tempting. The interim design would have been:

ha_llats:
  - label: "HA (Admin)"
    token: "<LLAT>"        # stored as schema: password
  - label: "HA (Bot)"
    token: "<LLAT>"

…with setup.sh creating a NyxID service per entry + pushing the LLAT via nyxid node credentials add locally. Functionally works, but makes the add-on a credential-delivery bridge that every other NyxID-fronting project would also have to reimplement. It also persists LLATs in HA's add-on options storage, which is a second place they live beyond the user's HA user accounts — rotation and audit get awkward.

Waiting on NyxID #418 is the right call: that lets credentials stay in NyxID where they belong, and the add-on stays thin.

Interim workaround (documented, not built-in)

Users who need this TODAY can already achieve it via the existing generic services[] config field:

services:
  - slug: ha-admin
    target_url: "http://homeassistant.local:8123"
    credential_type: header
    credential_name: "Authorization"
    credential_value: "Bearer <LLAT>"      # note: user must prefix 'Bearer '

Requires host_network: true (already enabled) so homeassistant.local resolves inside the container.

We could add a README snippet pointing this out as a stopgap, but we'll leave the proper UX to the NyxID side.

Acceptance criteria (when #418 lands)

  • Verify NyxID #418 credential-delivery mechanism works with our node agent version
  • Document in README: "To expose additional HA LLATs, add a service in NyxID pointing at your add-on's node — see [link]"
  • Optionally: add-on startup log prints the node UUID and "add services at nyx.chrono-ai.fun pointing here"
  • Delete any half-baked ha_llats config scaffolding if we ever shipped it in an alpha

Related

  • NyxID #414 — browser wizard for bearer/via-node service add (clean UX for step 2 above)
  • NyxID #418 — BLOCKER — server-side credential management
  • NyxID #419 — credential_type state machine (partly mitigated by #418)

Will pick this up when NyxID #418 is in a tagged release.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions