The JSON API already gates correctly: GET / with Authorization: Bearer <API_TOKEN> returns all projects, anonymous gets only mode=attested/public (proxy/ingress.py:114-117 — visible = [p ... if authed or p.mode == "attested" or p.public]).
But the landing viewer (proxy/templates/index.html:62) fetches anonymously with no way to supply the token — no template has any auth/localStorage. So the pod owner browsing their own pod sees only the attested+public subset and there is no "logged in" state in the web UI at all.
Fix, viewer-only (no API change needed):
- An "owner token" affordance on the landing page (e.g. small login link → prompt), stored in localStorage
- When set, attach
Authorization: Bearer <token> to the listing fetch; on 401/mismatch just show anonymous view and clear the badge (surface the failure, don't mask)
- Visually distinguish the additional non-attested projects (e.g. a
dev/unlisted badge using the existing mode/public fields already in the JSON) plus a "viewing as owner" indicator with a logout that clears localStorage
- Never render the token anywhere in the page after entry
Verification: test_daemon.py stays green; for the UI, curl the listing with and without the Bearer header and show the count differs, plus exercise the page (fetch path) if practical.
The JSON API already gates correctly:
GET /withAuthorization: Bearer <API_TOKEN>returns all projects, anonymous gets onlymode=attested/public(proxy/ingress.py:114-117 —visible = [p ... if authed or p.mode == "attested" or p.public]).But the landing viewer (proxy/templates/index.html:62) fetches anonymously with no way to supply the token — no template has any auth/localStorage. So the pod owner browsing their own pod sees only the attested+public subset and there is no "logged in" state in the web UI at all.
Fix, viewer-only (no API change needed):
Authorization: Bearer <token>to the listing fetch; on 401/mismatch just show anonymous view and clear the badge (surface the failure, don't mask)dev/unlistedbadge using the existing mode/public fields already in the JSON) plus a "viewing as owner" indicator with a logout that clears localStorageVerification: test_daemon.py stays green; for the UI, curl the listing with and without the Bearer header and show the count differs, plus exercise the page (fetch path) if practical.