feat: session identity, step-up approval, and OpenClaw-focused docs#13
Merged
Conversation
…ion auth Add the v1 session identity system foundation: - Role config schema (SessionConfig, RoleConfig) with namespace scope, allowed actions, bootstrap trust methods, and seal key requirement - New internal/session package with HMAC-SHA256 signed tokens (phxs_ prefix), in-memory session store with background cleanup - POST /v1/session/mint endpoint with structured denial codes (ROLE_NOT_FOUND, BOOTSTRAP_FAILED, SCOPE_EXCEEDED, etc.) - Session token auth path in authenticateInfo() between short-lived tokens and bearer fallback - Namespace scope enforcement in all secret handlers - Action enforcement per session role (default: list + read_value) - Seal key fingerprint binding at mint time, validated on requests - Session-authenticated requests bypass ACL seal key check (use session-bound fingerprint instead) - Loopback IP detection for "local" bootstrap trust method - Forward-compatible SessionID/SessionRole in audit Entry and policy RequestContext - 21 unit tests across session package, all existing tests pass - Version bump to 0.12.0 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…tructured denials Server: - Session renewal endpoint (POST /v1/session/renew) with re-validation of role config, bootstrap trust, and attestation requirements - Auth model: session tokens checked before mTLS so renewal requests can carry both session identity and current mTLS attestation evidence - Role attestation enforcement at mint and renew (require_mtls, source_ip, cert_fingerprint) - ACTION_DENIED code (was SCOPE_EXCEEDED) for session action denials - Cache-Control: no-store on mint and renew responses - "token" added to valid bootstrap methods - Action name validation against known set in config - Session-aware audit logging (LogSessionAllowed/LogSessionDenied) with session ID propagation across all handler audit call sites CLI: - Auto-mint via PHOENIX_ROLE env var (takes precedence over PHOENIX_TOKEN) - Session token caching with per-role keys - Seal key auto-generation and persistence (~/.phoenix/session-seal-<role>.key) - Transparent renewal when nearing expiry (10 min buffer) - Structured denial parsing in handleError() with code/detail/hint format MCP: - Background session renewal goroutine (5 min interval) - Structured denial formatting in all tool handlers SDK: - NewWithRole() for fail-closed session minting - MintSession() and RenewSession() methods - Auto-renewal in doRequest() (5 min buffer) - Error type extended with Code and Remediation fields Phase 1 non-blockers fixed: - "token" in validBootstrapMethods - Audit SessionID populated via session-aware methods - Cache-Control: no-store on mint response - Role Actions validated against known names - ACTION_DENIED replaces SCOPE_EXCEEDED for action denials Tests: 14 new tests across session, config, and API packages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a role has step_up: true, session mint returns 202 with a pending
approval instead of a token. A human approves via `phoenix approve <id>`,
and the agent polls for status to receive the session token once approved.
New package internal/approval/ with in-memory store, cleanup goroutine,
and full lifecycle (pending/approved/denied/expired).
API: 4 new endpoints (/v1/approval/{id}, /v1/approval/{id}/approve,
/v1/approval/{id}/deny, /v1/approvals), step-up branch in session mint.
Security (review fixes):
- All approval endpoints require ACL admin authorization
- Status endpoint restricted to requester or admin; token only visible
to authorized callers
- Approval-time minting re-validates full current role config:
bootstrap trust, attestation, seal key, namespaces, actions, TTL
- Cert fingerprint stored on approval for attestation re-check
CLI: `phoenix approve` with interactive /dev/tty confirmation,
`pollForApproval` with 2s polling, TTY detection, same-TTY warning.
17 API tests + 11 approval store tests covering happy paths, denial,
expiry, admin-auth enforcement, non-admin rejection, stale role
re-checks (removed role, tightened bootstrap/attestation/seal key).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
API: GET /v1/sessions (list), GET /v1/sessions/{id} (info),
POST /v1/sessions/{id}/revoke. Session-token callers are strictly
scoped to their own session ID — no ACL escalation. Bearer/mTLS
callers see own-agent sessions; admins see/revoke all.
CLI: phoenix sessions list|info|revoke subcommands with table output,
optional --role/--agent filters.
MCP: HTTP 202 (APPROVAL_REQUIRED) handling in resolve/get/list tools
with agent-friendly remediation messages. New phoenix_session_list
and phoenix_session_revoke tools always advertised.
SDK: ListSessions(), RevokeSession(), SessionInfo struct, and error
classification helpers (IsApprovalRequired, IsSessionExpired,
IsScopeExceeded, IsActionDenied).
10 new API tests including sibling-session isolation, 3 SDK tests,
MCP tool count tests updated.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
… isolation Audit: structured denial codes (SESSION_EXPIRED, SESSION_REVOKED, SESSION_INVALID) on all auth failures instead of generic 401. ParseClaimsInsecure extracts agent/sessionID from expired tokens for audit logging. session.auth audit event with session_id context. Fix revoke audit to use session-aware helper. Security: session tokens now blocked on all admin/control-plane endpoints (authenticate() rejects UsedSession with ADMIN_AUTH_REQUIRED). Scoped session credentials cannot reach audit, agent, cert, status, policy, rotate-master, or token-mint endpoints even if the underlying agent has admin ACL. handleAuthError surfaces structured denial codes on all auth failure paths. SDK: add IsSessionRevoked() error helper. Docs: new session-identity.md guide covering roles, lifecycle, CLI, SDK, MCP, audit events, and denial codes. Updated api-reference-index, authentication, cli-usage, configuration docs. Release notes updated. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Session cache key now includes server URL hash, preventing collisions when the same role name is used across different Phoenix servers - Guard global token variable with sync.RWMutex for MCP background renewal goroutine safety - SDK TestNewDefaults uses t.Setenv to clear PHOENIX_SERVER/TOKEN, making the test hermetic regardless of shell environment Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add browser-based operator dashboard at /dashboard/ for approvals, sessions, audit, and role inspection. All assets embedded via go:embed. Dashboard: - Cookie auth (bcrypt password or PIN), HMAC-signed sessions, CSRF - Login rate limiting with exponential backoff per source IP - Secure cookie flag auto-detected from TLS/X-Forwarded-Proto - Approve/deny step-up requests with shared ValidateForMint checks - Session revoke, audit log with auto-refresh, role inspection - Dark industrial theme, mobile-responsive layout - Audit actions logged as dashboard@<client_ip> for forensic distinction Shared approval validation: - Extract ValidateForMint from api.go into approval package - Typed ValidationError with machine-readable codes - BootstrapAllowed and CheckAttestation as standalone functions - Both API handler and dashboard call the same safety checks Docs: - New docs/dashboard.md — full deployment guide, security model, deployment checklist, transport security requirements - Rewrite docs/threat-model.md — dashboard attack surface, session identity threats, threat/mitigation/residual-risk table - Update getting-started, authentication, api-reference-index, lan-deployment, session-identity, configuration docs Tests: 10 dashboard, 7 approval validation, 7 config validation (new) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Logout now requires valid cookie + CSRF (was unprotected POST) - Audit events added: dashboard.logout, dashboard.auth (expired cookie), dashboard.csrf (token mismatch) - Docs: audit trail table updated with all event types, threat model updated with full audit coverage, release notes expanded - 7 new tests for audit behavior and logout auth - ExampleConfig includes session + dashboard sections Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ogin (v0.12.9) Password storage: - Config field changed from plaintext `password` to `password_hash` (bcrypt hash). Plaintext rejected by validation. - Added `phoenix-server --hash-password` to generate hashes interactively. - Dashboard stores hash directly; no hashing at startup. Single active session: - Default: only one dashboard session at a time. Second login rejected with "another session is active" message. - Force Login button appears on blocked login page — re-authenticates and invalidates the prior session via nonce rotation. - Logout and cookie expiry clear the active nonce so new logins proceed. - `allow_multi_login: true` config option disables enforcement. Non-blocker fix: - password_hash validation checks bcrypt prefix AND minimum length (59 chars), catching truncated hashes. Tests: 5 new (single-session block, force takeover, logout-then-login, multi-login mode, force-login bad credential). 22 total dashboard tests. Docs: dashboard.md, configuration.md, threat-model.md, getting-started.md, lan-deployment.md updated for password_hash, single-session, force login. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Code changes for v0.13.3 release readiness:
- Add DELETE /v1/agents/{name} endpoint and `phoenix agent delete` CLI
command. Backend (ACL.RemoveAgent) already existed but was never wired
to API or CLI. Includes self-delete protection and audit logging.
- Add `phoenix-server --reissue-cert --san <ip|host>` to re-issue the
server TLS certificate with custom SANs for LAN deployment. Uses
existing CA, always includes localhost/127.0.0.1.
- Fix staticcheck S1000 (for-select single case) in approval poll loop
- Fix staticcheck S1011 (append loop) in cert reissue
- Fix gofmt alignment in DashboardConfig and Client structs
- Fix TypeScript SDK test env leak (PHOENIX_SERVER bleed-through)
- Bump version to 0.13.3
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comprehensive doc review and truth pass across all public documentation: - Fix broken first-run: README and getting-started used https:// but default init starts plain HTTP on loopback. All quick-start examples now use http://127.0.0.1:9090 with clear notes on when/how to enable TLS. - Fix LAN deployment: added missing auth.mtls.enabled step, replaced nonexistent --san flag with real --reissue-cert workflow, added full executable walkthrough. - Rewrite roadmap to reflect shipped state (dashboard, HTTP MCP, session identity were listed as planned/in-progress but are shipped). - Add Session Identity and Dashboard rows to README docs table. - Expand cli-usage.md with missing commands: agent create/delete, cert issue/revoke, keypair generate, status, verify, emergency, rotate-master, policy show/test. - Add Go SDK section to integrations.md; mark Python/TS packages as not yet published on PyPI/npm. - Add transport security section to configuration.md explaining the HTTP-by-default story. - Document in-memory session/approval state and restart behavior. - Document role scope vs ACL intersection semantics. - Fix admin-token-lifecycle.md stale https:// and CA_CERT references. - Fix getting-started.md sample startup output (showed mTLS enabled on default config). - Fix config.example.json: listen address to 127.0.0.1, paths to /data/phoenix/, added dashboard password_hash placeholder. - Relabel reference-only-enforcement-design.md from WIP to RFC. - Update RELEASE_NOTES.md: add version header, add HTTP MCP transport. - Update api-reference-index.md with agent delete endpoint. - Remove Docker "(planned)" label — images are published. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Rework README opener with origin story and agent framework context. Consolidate OpenClaw integration docs with containerized deployment guide and honest limitations note. Fix localhost URL inconsistencies across migration and dashboard docs. Rewrite comparison table as 3-column (.env / SecretRef / Phoenix). Lead with concepts over jargon throughout. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Notes
0.13.3v0.13.3has been pushed