---
url: https://clusto.app/docs/session-credentials.md
description: >-
  The limited Clusto credential sessions get when they run as a non-root account
  - who gets which credential, what an agent can and cannot do with it, the
  same-account rule, expiry, the security.session_credentials flag, and how to
  run admin commands.
---

# Session Credentials

Every terminal, chat, team member and task run that Clusto starts needs a way to
talk back to its daemon: the `clusto` CLI inside the session, the chat and team
tools, the report and notes tools, the hooks. That access is a token in the
session's environment (`CLUSTO_TOKEN`, also set as `HIVE_TOKEN`).

By default that token is the node's admin token. When a session runs as another
operating-system account (a project's **Run As**, or the node's
`default_session_user`), handing it the admin token would let anything running
as that account control the whole node. **Session credentials** close that gap:
a session that runs as a non-root account gets a **limited credential** that
works only on this machine and only while the session lives.

## Who gets which credential

| Session | Credential |
|---------|------------|
| Runs as root, or as the account the daemon itself runs as | The node admin token. That account can read `config.toml` anyway, so nothing is gained by limiting it |
| Runs as any other account (Run As, `default_session_user`) | A limited **agent** credential |
| Any Clusto Assistant chat | A narrower **assistant** credential, whatever account it runs as |
| The access file `local-daemon.toml` of another account | A limited agent credential (see below) |

On Windows every Run As session counts as another account, so it gets a limited
credential.

The credential is minted when the session starts and is not stored anywhere. It
looks like `cst1.<payload>.<signature>`: it names the account and the session,
and is signed with a key derived from the node admin token and the node id.
Rotating the admin token therefore revokes every credential at once, and a
credential minted on one node is not accepted by another node of the cluster.

## The access file

Clusto writes `local-daemon.toml` in each account's Clusto config directory
(`~/.config/clusto/` on Linux) so the `clusto` CLI works out of the box for that
account. For an account other than the daemon's, that file now holds a limited
agent credential instead of the admin token, because every process of the
account can read it. As a result:

* `clusto daemon get-token` prints the credential **that account holds**. To get
  the admin token run it with `sudo`, or read it from the node's `config.toml`.
* Commands that need admin rights (see below) fail for that account until you
  pass the admin token: `clusto --token "$T" ...`, a saved
  [profile](/cli#clusto-profile-saved-connection-profiles), or run them from the
  Clusto app.
* If the credential is re-issued for a different account, the previous one stops
  working.

## What a limited credential can do

Both kinds can list and read: sessions, projects, teams, tasks, reports, notes
(read, search and write), and the cluster status. A chat can also rename itself
and read its own context.

The **agent** credential also allows:

* posting and updating [reports](/reports) and attachments;
* reading and proposing [lessons](/knowledge) (approving lessons is done in the
  app);
* reading team details and rosters, and setting the session's own attention
  state;
* managing [teams](/teams) and [tasks](/tasks) that run as the same account
  (below), and killing, renaming or tagging sessions of that account.

The **assistant** credential also allows reading the cluster configuration, task
run history, the GitHub and Azure DevOps snapshots and the daemon log, and proposing
an action inside its own chat. Actions still wait for your approval in the app.

A limited credential **cannot**: open a terminal or send input to one
(`clusto new`, `open`, `send`, `attach`, `export`, `adopt`), read or write files
or run git operations through the daemon, change projects, agent docs or
settings, change the cluster, SSH connections or updates, approve lessons,
control chats, or link a node to your account. It receives none of the live
broadcast updates other clients get, never receives the cluster token, and sees
task environment values masked.

## The same-account rule

Anything that starts work must run as the account the credential belongs to,
and only on the node the credential was issued by:

* Creating or changing a **team** requires the team's account to be the same as
  the session's, every live member to run as that account on this node, and the
  team's working directory to be owned by that account.
* Creating, changing, triggering or cancelling a **task** requires the task to
  belong to this node and its runs to resolve to the same account (the
  project's Run As, else `default_session_user`). Task `env` may not set
  loader and runtime variables such as `LD_PRELOAD`, `LD_LIBRARY_PATH`,
  `GLIBC_TUNABLES`, `MALLOC_*` or `DYLD_*`.
* Killing, renaming or tagging a **session** works for the session itself and
  for sessions of this node that run as the same account.
* Requests aimed at another node are refused.

If an agent needs to start work as a different account, set the project's Run As
(or the node's default session user) to the agent's account, or do it from the
app.

## Where it is accepted, and how it ends

* **Local only.** The daemon accepts a session credential only from the
  machine it runs on (loopback or one of the host's own addresses). It is useless
  from the tunnel, the web relay or another host. A reverse proxy on the same
  host makes remote clients look local, so do not put one in front of the client
  port.
* **It dies with its session.** A credential bound to a session stops working
  once the session ends (killed, exited or removed). A connection that is already
  open is closed within about 15 seconds. The access-file credential lasts as
  long as it is the current one for its account.
* **Wrong token versus expired.** A leftover helper that presents an ended
  session's credential gets "session credential expired: its session ended",
  not "invalid token", and does not count as a failed login.

## Messages you may see

| Message | Meaning |
|---------|---------|
| `<request> is not permitted with a session credential. ...` | The action is on the denied list. Run it from the app or with the admin token |
| `<request> would run as <account> on this node, but this session credential belongs to <other>` | The same-account rule. Set Run As to the session's account, or use the admin token |
| `<request> is refused: a session credential only controls work on its own node` | The target is on another node |
| `<request> is refused: <dir> is not owned by <account>` | A team's working directory belongs to someone else |
| `session credential expired: its session ended` | The session the credential belonged to is gone |

## Running admin commands

A limited session cannot do admin work, by design. To run an admin command
yourself, use the app, or pass the node admin token explicitly with the global
`--token` flag (it goes before the subcommand) or `CLUSTO_TOKEN`. Prefer a saved
profile that you create once outside the session: a `--token` value on a command
line can be read by other local users in the process list.

```bash
clusto profile add admin --token "$ADMIN_TOKEN"   # run once, outside the session
clusto --profile admin new --dir /srv/project
```

Do this only for accounts you trust with the whole node.

## The release flag

Minting limited credentials is controlled by the `security.session_credentials`
release flag (node scope). It is **off by default**: with the flag off every
session keeps the admin token exactly as before, and the credentials described
above are not issued. Verification and the permission checks are always on, so a
limited credential is enforced as soon as one exists.

Turn it on for a node with the `[features]` table in its `config.toml`, or
remotely through the published `flags.json` (see [Feature Flags](/feature-flags)):

```toml
[features]
"security.session_credentials" = true
```

Sessions started after the change get the new credential. The flag is removed in
1.16, and limited credentials then become the behavior.
