# Identity

Cotal gives each peer an identity and a set of broker-enforced permissions. A peer can publish as itself and read only through the grants on its connection. These guarantees depend on a trusted broker and signer, and on receivers checking the sender.

[SPEC §2](/docs/spec/#2-identity), [§9](/docs/spec/#9-nats--jetstream-security-and-authorization), [§10](/docs/spec/#10-connection-and-onboarding), and [Appendix B](/docs/spec/#appendix-b-profile-acls) define the contract. The [security model](/docs/security/) explains the threats and limits.

## On by default

`cotal up` creates a space with JWT authentication. `cotal up --open` creates an unauthenticated development mesh. Both bind to loopback by default.

`--host 0.0.0.0` changes the network bind independently of authentication. Open mode is outside the security guarantees in [SPEC §9](/docs/spec/#9-nats--jetstream-security-and-authorization).

## Shared identity

A principal is an `owner.actor` pair. The owner identifies the human or organization the peer acts for. The actor is that peer's handle within the owner. The pair appears in its card ID, sender subjects, presence key, and consumer names.

Open development meshes use owner `local`. Per-user authentication derives an opaque owner token, `u_` followed by 26 base32 characters. The token avoids putting the person's identity in routing subjects.

A locally generated nkey authenticates a connection. The signer receives its public key. The nkey is distinct from the principal, and static connections use it to scope their reply inbox.

The broker pins sender tokens in publish subjects to the connection's principal. A peer cannot publish as another owner or as a sibling actor. Receivers must also reject a payload whose `from.id` differs from the subject sender. Both checks are required for sender authenticity ([SPEC §3](/docs/spec/#3-subject-layout), [§5](/docs/spec/#5-envelopes)).

Each space is a NATS account. The broker operator signs that account, and the account signing key mints per-agent user JWTs.

## Provisioner

The provisioner holds signing authority. It mints scoped credentials and creates the DM and role-task consumers that agents can bind but cannot create for themselves. The manager can host this work, but a space does not require a manager.

Out-of-band minting is a static-auth operation. Its credentials expire after 24 hours by default; `--no-expiry` opts out of that bound. Reusing an identity does not reuse its lifecycle. [Provisioning and credential limits](/docs/identity-authority/#provisioning) lists the options and refusal conditions.

## Profiles

A profile is a default-deny allow-list for a credential. The reference implementation builds permissions from the same subject, stream, and durable-name builders as the wire layout.

An `agent` reads within its channel ACL and its own inboxes. An `observer` reads chat and presence. An `admin` adds elevated messaging reads, including DMs, while remaining read-only. Operator and workflow duties use separate, narrower profiles.

An agent's channel configuration distinguishes what it reads at boot (`subscribe`), what it may read (`allowSubscribe`), and where it may post (`allowPublish`, default-deny). [Channels and permissions](/api-reference/channels-and-permissions/) explains the configuration. The [profile reference](/docs/identity-authority/#profiles) preserves each profile's grants and consumer limits.

DM and task consumers are pre-created and bind-only. This prevents a peer from creating a consumer that reads another principal's DM inbox or another role's queue.

## Issued authority

A caller's identity alone does not prove the permission ceiling accepted by its issuer. For an issued credential, the issuer records that ceiling before releasing the credential. A generation in the endpoint subject binds requests to that record.

Workflow admission requires this binding. Renewals preserve a generation only while the ceiling stays identical. The [issued-authority reference](/docs/identity-authority/#issued-authority) explains the stores, endpoint rails, user-auth eligibility, and refusal boundaries.

## Declared capabilities

Agent files declare control authority. `capabilities: [spawn]` permits spawning, control of the caller's own children, and persona definition. `capabilities: [run]` adds workflow-run commands and includes the spawn set because a workflow may spawn agents.

Without these capabilities, a peer retains self-despawn and the run-turn operations addressed to it. The exposed tools follow the grant. Persona content edits cannot add capabilities. See [capability grants](/docs/identity-authority/#capabilities) for the full command and tool boundary.

> **Warning: Spawn grants authority on the manager host**
>
> On a static mesh, a spawn-capable caller can choose its child's channel ACL. Spawn also permits connector launch options on the manager host. Treat it as host-launch and ACL authority. Read the [host boundaries](/docs/security-boundaries/#spawn-authority) before granting it.



## Per-user authentication

With `cotal up --user-auth --idp <auth base URL>`, people sign in through an external identity provider. The auth service checks the actor ledger at every connection and mints that connection's scoped credential. The manifest equivalent is `broker.auth: "user"`.

The first enable pins the IdP. Later enables cannot replace it with a different IdP. A missing grant denies access. User-auth commands refuse missing login or unavailable auth service rather than trying static credentials.

Ordinary delegated agents stay inside their owner's channel and capability envelope. Checks follow the delegation chain to an authority root at grant time and at bearer exchange. Revocation reaches descendants in that chain. An admin-scoped ancestor is a separate authority root and ends containment checks. [User-auth lifecycle](/docs/identity-user-auth/#delegation) covers this boundary and the ledger, catalogs, chat sessions, views, retirement, and recovery.

### Enrollment redeem

An owner can give a remote seat a one-time enrollment URL when the seat has no browser, TTY, or cached login. The client redeems it once without redirects or retries. The token expires five minutes after minting.

The URL is secret. It is neither persisted nor forwarded to children. The [enrollment contract](/docs/identity-user-auth/#enrollment) gives the URL checks, response fields, and deliberately indistinguishable refusal cases.

### Remote manager authority

Running a remote manager requires the separate `supervise` ledger scope. Neither `spawn` nor `admin` grants persistent manager registration authority.

The host issues authority for one owner and one manager instance. The remote manager receives no signer or general mint API. If the host service or renewal is unavailable, it refuses new launches and replacement credentials. [Remote manager authority](/docs/identity-user-auth/#remote-manager-authority) explains registration, recovery, and version-skew behavior.

### Callout deadlines

The auth service bounds callout work, queueing, and slow requests. See [callout deadlines](/docs/identity-service-auth/#callout-deadlines) and [connect limits](/docs/identity-service-auth/#connect-limits) for defaults, tuning, and refusal behavior.

### Connect limits

The broker authorization timeout and callout concurrency are separate limits. See [connect limits](/docs/identity-service-auth/#connect-limits).

### Held agent names

A refused name can identify a live actor, pending retirement, or a live lifecycle head. No rename or local deletion proves that authority ended. See [held agent names](/docs/identity-user-auth/#held-agent-names).

## The IdP callout contract

The low-level bridge accepts EdDSA/Ed25519 JWTs against pinned keys, issuer, and audience. The stock login and provider flow expects Better Auth's device-code endpoints and conventions. A different production IdP needs host login and provider wiring. An RS256 or ES256 issuer also needs normalization or re-issuance.

[Auth service and IdP integration](/docs/identity-service-auth/) describes both listeners, the bridge hooks, owner derivation, and proof requirements. Better Auth is a development and test fixture, not a runtime dependency.

## Joining

A join link carries server, authentication, and space ([SPEC §10](/docs/spec/#10-connection-and-onboarding)).

```text
cotals://<token>@host:4222/<space>?channel=general
```

`cotals://` requires TLS. `cotal://` does not require TLS and permits downgrade attacks on an untrusted network.

People use `cotal join --link …`. Agents can set `COTAL_LINK=…`, which the connector expands to join. Token and username/password links belong to the open-mode path. The default authenticated path uses a minted credential file, and the endpoint adopts its principal as the card ID.

A managed seat reads credentials through [launch material](/api-reference/config/#launch-material). Managed launches avoid putting `COTAL_CREDS` in an environment inherited by every descendant process. A manually driven session sets `COTAL_CREDS` itself.

## Honest limitations (v0)

The signer remains trusted, static copied credentials can remain broker-valid until expiry or key rotation, and the system-account credentials need scheduled renewal. Broker-authenticated senders are not portable signatures. Chat and role-task metadata have visibility limits distinct from message content.

[Credential lifetime and rotation](/docs/security-boundaries/#credential-lifetime) records the TTLs, rotation procedure, backup consequence, and hosted renewal option. The [security model](/docs/security/) describes metadata exposure and the host boundary.

An ACL-denied publish reaches the endpoint's error path as a logged denial. [Run a mesh](/docs/run-a-mesh/) explains this diagnostic behavior.

## Standalone endpoint callers

Static `auth mint <name> --endpoint <class> --out <private-file>` can create a private native agent credential for supported endpoint calls. It adds explicit request rows from a fresh, digest-verified description and preserves the registered broker TLS policy.

Only untargeted synchronous ephemeral commands are supported. The paired intent is a local coordination record, not broker admission, issued authority, or lifecycle proof. The [standalone caller reference](/docs/identity-authority/#standalone-callers) lists the checks and unsupported cases.

[Credential profiles and issued authority](/docs/identity-authority/)

Look up mint options, profile limits, capabilities, and standalone caller checks.


[Security model](/docs/security/)

Review adversaries, broker guarantees, and limits before choosing a deployment.
