Agent Token Security Plan
Add **Node-local agent tokens** so Harbor Node can require a real credential for network action calls and attach those calls to a stable per-agent identity.
Agent Token Security Plan
Summary
Add Node-local agent tokens so Harbor Node can require a real credential for network action calls and attach those calls to a stable per-agent identity.
This should unlock:
- per-agent or per-integration credentials
- per-agent permissions
- cleaner audit attribution
- better approval attribution
- token revocation and deletion
- future per-agent rate limits and policy overlays
This plan is intentionally Node-local first. It should not depend on Cloud, Fleet, billing, or the public website.
Why This Matters
Today Harbor Node accepts action execution requests on the local API without a first-class Node-issued bearer credential model.
Relevant current wiring:
- live action execution happens at apps/harbor-node-api/src/index.ts on
POST /v1/actions/:actionId/execute - the current route trusts
requestedByfrom the request body and writes that into audit and approval records - approvals and audit already exist and are good places to attach a stronger caller identity
- Harbor UI already shows audit and approval behavior, so this feature can integrate into an existing operator surface instead of inventing one from scratch
This means we can add a real auth layer without replacing Harbor Guard, Harbor audit, or the action model.
Security Position
Do not use an 8 to 10 character bearer token for real network auth.
Recommended structure:
agentId: short, human-friendly identifier for UI and logstoken name: human-friendly label such asClaude Desktop,OpenCode Agent, orNightly Gmail Workersecret token: random opaque bearer token, one-time reveal only
Recommended secret length:
- minimum: 16 random characters
- preferred MVP: 20 to 24 random characters
Recommended storage:
- store only a token hash
- optionally store a short fingerprint for UI display
- never log the raw token
- never return the raw token after creation
Scope
In Scope For Pass 1
- Node-local token storage in SQLite
- create / list / revoke / delete token management
- one-time secret reveal UI
- token hashing and verification
- permission scopes on the token
- protect remote action execution with bearer token auth
- use resolved token identity in audit and approval records
- basic last-used tracking
Explicitly Out Of Scope For Pass 1
- Cloud sync of tokens
- website account token management
- Fleet-wide token replication
- org / team management
- token expiry policies
- IP allowlists
- OAuth for agents
- signed request schemes
- mTLS
- broad auth across every Harbor route
Current Wiring Notes
Execution route
Current execution is handled in apps/harbor-node-api/src/index.ts.
Current behavior:
- local audit events - approval records - optional cloud activity sync metadata
- route:
POST /v1/actions/:actionId/execute - request body includes
requestedBy - route writes
requestedByinto:
Existing attribution model
Shared caller and audit shapes already exist in packages/shared/src/index.ts.
This is useful because we do not need to invent a whole new audit model. We can resolve the token into a stable HarborActor and feed that into the existing system.
SDK
The SDK in packages/sdk-ts/src/index.ts already centralizes requests and can be extended later with optional bearer token support for headless agents.
Proposed Model
Agent profile
Add an optional agent profile concept.
Purpose:
- group one or more tokens under one logical agent identity
- allow better audit naming
- allow future per-agent policy and limits
Fields:
agentIdnamedescription?statuscreatedAtupdatedAt
Recommended MVP:
- start with agent profiles present in the model
- token creation requires linking to one profile
- allow one token per agent as the normal path
Agent token
Fields:
tokenIdagentIdnamepermissionstokenHashtokenFingerprintcreatedAtlastUsedAt?revokedAt?status
Token secret format:
- opaque random bearer string
- optional prefix for recognition such as
hn_
Example:
hn_A7f2mPq91Lx4Vr8K
Permission model
Start route-based, not hyper-granular.
Recommended MVP permissions:
actions.executeactions.readports.readapprovals.readapprovals.resolveaudit.readsettings.read
Do not start with dozens of fine-grained per-action scopes.
If later needed, add:
- per-port scopes
- per-category scopes
- read-only versus execute-only subsets
Data Model
Add SQLite tables in apps/harbor-node-api/src/store.ts.
agent_profiles
Columns:
agent_id TEXT PRIMARY KEYname TEXT NOT NULLdescription TEXTstatus TEXT NOT NULLcreated_at TEXT NOT NULLupdated_at TEXT NOT NULL
agent_tokens
Columns:
token_id TEXT PRIMARY KEYagent_id TEXT NOT NULLname TEXT NOT NULLpermissions_json TEXT NOT NULLtoken_hash TEXT NOT NULLtoken_fingerprint TEXT NOT NULLstatus TEXT NOT NULLlast_used_at TEXTrevoked_at TEXTcreated_at TEXT NOT NULLupdated_at TEXT NOT NULL
Indexes:
idx_agent_tokens_agent_ididx_agent_tokens_status
Foreign key:
agent_id -> agent_profiles.agent_id
API Design
Add shared contracts in packages/shared/src/index.ts.
Management routes
GET /v1/agent-profilesPOST /v1/agent-profilesGET /v1/agent-tokensPOST /v1/agent-tokensPOST /v1/agent-tokens/:tokenId/revokeDELETE /v1/agent-tokens/:tokenId
Creation response:
- return token metadata
- return plaintext token once
List response:
- name - linked agent - permissions - created - last used - status - fingerprint
- no plaintext token
- show:
Authenticated execution routes
Pass 1 should require bearer token auth for:
POST /v1/actions/:actionId/execute
Pass 1 can optionally protect more read routes later, but action execution is the important first boundary.
Bearer format:
Authorization: Bearer <token>
Behavior:
- missing token ->
401 - invalid token ->
401 - revoked token ->
403 - missing permission ->
403
Execution Flow
Token creation
- Operator opens Token Manager in Harbor UI.
- Operator creates or selects an agent profile.
- Operator chooses token name and permissions.
- Harbor generates a secret token.
- Harbor stores only the hash and metadata.
- Harbor shows the secret once in a modal.
- Operator copies it into the target agent environment.
- After modal close, the secret is gone.
Action execution
- Agent sends bearer token in
Authorizationheader. - Harbor verifies token hash.
- Harbor resolves token to agent profile and permissions.
- Harbor maps that into
requestedBy. - Harbor checks token permission.
- Harbor runs existing Harbor Guard policy.
- Harbor writes audit / approval / cloud activity using the resolved token identity.
UI Plan
Add a new Harbor UI page or section called Security.
Recommended layout:
Agent ProfilesAgent TokensCreate TokenRevoked Tokens
Agent profile card
- name
- description
- token count
- last used token time
Token list row/card
- token name
- linked agent
- permission pills
- fingerprint
- created at
- last used at
- status
- revoke button
- delete button
Create token modal
Fields:
- profile or agent selection
- token name
- permission checklist
After creation:
- one-time token reveal
- copy button
- confirm close
UX guardrails
- do not show the full token after creation
- make revoke obvious and low risk
- make delete destructive only after revoke or confirmation
- explain that one token per agent is the recommended default
Shared Contract Additions
Add types for:
HarborAgentProfileHarborAgentTokenSummaryHarborAgentTokenCreateRequestHarborAgentTokenCreateResponseHarborAgentTokenListResponseHarborAgentTokenRevokeResponseHarborAgentProfileCreateRequestHarborAgentProfileListResponse
SDK Additions
Extend packages/sdk-ts/src/index.ts.
Recommended additions:
- list profiles - create profile - list tokens - create token - revoke token - delete token
- optional
bearerTokenin client options - request helper adds
Authorization: Bearer ... - management helpers for:
Do not make bearer token mandatory for Harbor UI’s current operator calls unless that becomes a separate milestone.
Audit And Approval Integration
Resolved token identity should be written into the existing audit system.
Recommended actor mapping:
kind: "agent"name: <agent profile name>
Add detail metadata:
agentIdtokenIdtokenNametokenFingerprint
Important:
- audit should not store raw bearer token
- cloud activity sync should keep only safe derived identity fields
Pass Breakdown
Pass 1A: Storage and shared contracts
- add shared types
- add SQLite tables and migrations
- add hash / verify helpers
- add store methods
Pass 1B: Node API management routes
- list/create/revoke/delete token routes
- profile list/create routes
- one-time secret creation response
Pass 1C: Execution auth
- require bearer token on
POST /v1/actions/:actionId/execute - permission checks
- audit attribution through resolved token identity
Pass 1D: Harbor UI
- add
Securitypage - token list
- create token modal
- revoke/delete actions
- one-time reveal modal
Pass 1E: SDK support
- optional bearer token support
- management helpers
Guardrails
- do not trust
requestedByfrom body when a bearer token is present - do not log raw tokens
- do not store raw tokens
- do not introduce Cloud dependency
- do not bypass Harbor Guard approvals
- do not protect every route in Pass 1
- do not overcomplicate scopes before the base model works
Open Decisions
Agent profile required?
Recommendation:
- yes, but lightweight
Reason:
- lets us cleanly support “one token per agent” while still allowing rotation later
Token length
Recommendation:
- 20 to 24 random characters
Reason:
- short enough to copy
- long enough for real auth
Execution-only or broader API auth?
Recommendation:
- start with execution-only
Reason:
- it secures the highest-risk route first
- avoids blocking operator UI work before the model is mature
Test Plan
Storage and API
- create profile succeeds
- create token succeeds
- plaintext token appears only in create response
- list tokens never returns plaintext
- revoked token cannot execute
- deleted token disappears from list
- invalid token returns
401 - token missing required permission returns
403
Execution and audit
- valid token can execute allowed action
- audit event shows agent identity
- approval request shows agent identity
- cloud activity sync uses safe caller metadata
UI
- token create modal shows one-time reveal
- copy button works
- revoke changes status immediately
- delete removes token from list
- permissions render clearly
Recommended First Milestone
Implement Pass 1A through Pass 1C first.
That gives Harbor:
- real token storage
- real execution auth
- real audit attribution
Then add the Harbor UI management surface as the next vertical slice.