Better-PaaS
Guides

Agent Access & Audit Logs

Create scoped agent tokens for AI tools, CI/CD, and automation. Track every action with audit logs.

Better-PaaS now supports scoped agent tokens - separate credentials for machines and AI assistants that are limited to only the actions they need. Every action they take is recorded in an audit log you can review.

This means you can let Claude Code deploy from your terminal, a GitHub Action push on every commit, or a monitoring script check health - all without sharing your admin password.

Fastest path: use the paas CLI

Run paas connect https://your-dashboard-url, then paas setup, and restart your editor. Sign in in the browser, pick a permission profile, and you're done - no curl, no copying admin tokens locally. See PaaS CLI - Connect from Your Machine.


What are agent tokens?

Your admin token is the master key. Agent tokens are scoped copies designed for specific jobs:

  • Scoped: Each token can only do what you allow. A log-reader agent can't delete apps.
  • Revocable: Delete a token instantly without changing your admin password.
  • Auditable: Every action appears in the audit log with the agent's name.
  • Free: Create as many as you need. No per-seat pricing.

When to use them

SituationUse this scope
Claude Code or Codex managing deploys from the terminalapps:read, apps:write, deploy:trigger, logs:read
GitHub Actions auto-deploying on pushapps:read, apps:write, deploy:trigger
A monitoring script checking uptimeapps:read, metrics:read
A teammate who needs to read logsapps:read, logs:read
An internal dashboardapps:read, metrics:read, logs:read
Full automation (dangerous, use carefully)apps:read, apps:write, apps:delete, plus any others

Creating an agent token

Use the paas CLI on your local machine:

paas connect https://paas.example.com

Sign in with your admin token in the browser, choose a profile (Observer, Deployer, or Operator), and authorize. A scoped bpagt_… token is saved to ~/.paas/config.json.

Then run paas setup and restart Cursor or Claude Code for native MCP tools.

Your admin token is used only in the browser session - it is not stored on your laptop.

Option B - API with curl (advanced)

Create tokens manually when you need custom scope lists or headless CI.

1. Get your admin token

On your server
cd ~/better-paas/backend && ./server token

Or read it from the file:

On your server
cat backend/data/admin_token.txt

2. Create the agent

ADMIN_TOKEN="your-admin-token-here"

curl -X POST http://localhost:8080/api/agents/create \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Claude Code - Local Dev",
    "scopes": [
      "apps:read",
      "apps:write",
      "deploy:trigger",
      "logs:read",
      "metrics:read",
      "addons:manage"
    ]
  }'

Response:

{
  "id": "a1b2c3d4e5",
  "name": "Claude Code - Local Dev",
  "scopes": ["apps:read", "apps:write", "deploy:trigger", "logs:read", "metrics:read", "addons:manage"],
  "createdAt": "2026-07-02T14:32:00Z",
  "token": "bpagt_ac7f83b2...91f4"
}

Copy the token now

The raw token is shown only once and can never be retrieved again. If you lose it, you must rotate the agent to generate a new one.


Scope reference

Choose only the scopes an agent needs. This is the principle of least privilege.

ScopeAllowsExample jobs
apps:readList apps, view details, read runtime logs, view metricsMonitoring, read-only dashboards
apps:writeDeploy, redeploy, stop, start, update, rollback appsCI/CD, AI deploy assistants
apps:deletePermanently delete appsCleanup scripts
addons:manageCreate, delete, attach, detach databases and cachesDev environment provisioning
servers:manageAdd or remove target serversInfrastructure automation
deploy:triggerCreate new deployments from Git or uploadGit push auto-deploy
logs:readRead app and build logsDebugging assistants
metrics:readRead CPU, memory, disk metricsMonitoring tools
system:manageDocker prune, system updatesMaintenance scripts
cron:manageCreate, update, delete, run scheduled jobsJob schedulers
backups:manageCreate, restore, delete backupsDisaster recovery
notifications:manageConfigure Slack/webhook notificationsAlert setup
agent:adminCreate, delete, rotate agent tokensMulti-admin delegation

Using an agent token

Agent tokens work exactly like your admin token - in the Authorization: Bearer header.

Using an agent token
AGENT_TOKEN="bpagt_ac7f83b2...91f4"

# List apps (requires apps:read)
curl -H "Authorization: Bearer $AGENT_TOKEN" \
  http://localhost:8080/api/apps

# Get a specific app

curl -H "Authorization: Bearer $AGENT_TOKEN" \
  "http://localhost:8080/api/apps/get?id=abc123"

# Deploy an app

curl -X POST http://localhost:8080/api/deploy \
  -H "Authorization: Bearer $AGENT_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "my-api",
    "gitRepo": "https://github.com/me/my-api",
    "branch": "main"
  }'

# Read logs (requires logs:read)
curl -H "Authorization: Bearer $AGENT_TOKEN" \
  "http://localhost:8080/api/apps/runtime-logs?id=abc123&lines=50"

If the agent is missing a required scope, the API returns:

{ "error": "Forbidden: missing scope apps:delete" }

Managing agents

List all agents

curl -H "Authorization: Bearer $ADMIN_TOKEN" \
  http://localhost:8080/api/agents

The response includes metadata - but never the raw token:

[
  {
    "id": "a1b2c3d4e5",
    "name": "Claude Code - Local Dev",
    "scopes": ["apps:read", "apps:write", ...],
    "createdAt": "2026-07-02T14:32:00Z",
    "lastUsedAt": "2026-07-02T15:10:00Z"
  }
]

Rotate a token (if lost or compromised)

curl -X POST http://localhost:8080/api/agents/rotate \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"id": "a1b2c3d4e5"}'

You receive a new token in the response. The old one stops working instantly.

Delete an agent

curl -X POST http://localhost:8080/api/agents/delete \
  -H "Authorization: Bearer $ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"id": "a1b2c3d4e5"}'

Audit logs

Every mutating action - deploys, deletes, stops, addon attaches, and so on - is recorded automatically. This includes actions by the admin token and every agent token.

Viewing audit logs

curl -H "Authorization: Bearer $ADMIN_TOKEN" \
  "http://localhost:8080/api/audit-logs?limit=20"

Response:

[
  {
    "id": "x9y8z7w6v5",
    "actorType": "agent",
    "actorId": "a1b2c3d4e5",
    "action": "app:deploy",
    "resourceType": "app",
    "outcome": "success",
    "ipAddress": "127.0.0.1",
    "createdAt": "2026-07-02T15:10:00Z"
  },
  {
    "id": "u4t3s2r1q0",
    "actorType": "admin",
    "actorId": "admin",
    "action": "addon:create",
    "resourceType": "addon",
    "outcome": "success",
    "createdAt": "2026-07-02T14:45:00Z"
  }
]

What gets logged?

  • Actor: The token type - admin for the main token, or an agent's ID.
  • Action: Human-readable like app:deploy, app:stop, addon:attach.
  • Resource: What kind of thing was affected (app, addon, server, etc.).
  • Outcome: success for authenticated requests.
  • IP address: Where the request originated.

Limits

  • Up to 500 entries per request (?limit=500).
  • Logs live in your SQLite database alongside app data.
  • There is no automatic pruning yet.

Security best practices

Never share the admin token. Create scoped agents for every tool and person instead.

Use the minimum scopes. An auto-deploy script does not need apps:delete.

Rotate tokens regularly. Especially CI/CD agents that might leak into build logs.

Monitor audit logs. Check /api/audit-logs weekly to spot unexpected activity.

Delete unused agents. If you stop using a tool or retire a server, delete its token.


Troubleshooting

"Forbidden: admin token required"

You are using an agent token to access /api/agents or /api/audit-logs. These endpoints require the admin token.

"Forbidden: missing scope X"

The agent was created without the scope needed for this action. Create a new agent with the correct scopes, or rotate the existing one.

"Unauthorized"

The token is wrong, expired, or the agent was deleted. Reprint the admin token with ./server token, or create a fresh agent.


Next steps

On this page