Authorization (IAM)
One policy engine decides every request, in every workspace, from the first request. There is no mode to switch on and nothing to enable: the settings you already maintain (roles, group grants, project permissions and API token scopes) are turned into decisions by a fixed set of built-in policies, and custom policies handle the exceptions.
Requires a Console release with the IAM engine
Everything in this section describes the IAM engine and the IAM center (Settings → IAM center). Releases that predate the engine decide access with the older role checks, and the pages, settings and API routes described here do not exist there. Parts that apply only to the Enterprise edition (portals) are marked where they appear.
This section is organized by task:
| Page | Read it when you want to |
|---|---|
| Authorization (IAM) (this page) | understand roles, levels, group grants, project permissions, token scopes and the built-in policies |
| Custom policies | freeze a service for a group, give a team temporary access, block writes from a network |
| Who can approve tool calls | appoint approvers for agent tool approvals, for example a compliance group |
| Who can see agent sessions | keep people to their own sessions, and control who can pick the bucket for session files |
| Webhook permissions | delegate webhook management and understand why receiver URLs are shown partly hidden |
| Portal access boundaries | restrict a portal to your networks, try it as an administrator, preview what a person would see |
| Acting for a user | let your application call the client API as its signed-in end users (X-Cognipeer-User-Token) |
| External users | manage the accounts that applications bring in, and give them access through groups |
| Troubleshooting and FAQ | read a refusal, replay a decision id, understand 403 and 503 answers |
| Upgrading to the policy engine | see who is affected before you upgrade, and roll out safely |
For signing in and API tokens see Authentication. For workspaces, projects and members see Multi-Tenancy.
How a request is decided
settings you maintain built-in policies your own policies
───────────────────── ───────────────── ─────────────────
workspace role six allow rules turn the allow or deny exceptions;
own service permissions effective level of a person → a deny always wins, an allow
group grants → or token into allow / deny never goes beyond the
project member permissions per service and level boundaries
API token scope six boundaries that no
custom policy can crossA request is allowed only when something allows it and nothing denies it. You do not have to write a policy to get a working system: roles, group grants, project permissions and token scopes already decide everything. Custom policies add to that, they do not replace it.
Every API route states how it is authorized:
| Declaration | Meaning |
|---|---|
| a service | The caller needs a level on that service (models, prompts, agents, ...). A read-only call (GET, HEAD, OPTIONS) needs read; anything else needs write; on an administration service a change needs admin. Most routes are this kind. |
| authenticated | Any signed-in person or valid API token of the workspace. The handler may still filter what the caller sees. |
| self | The handler authenticates the caller itself (signed links, machine tokens, shared secrets). |
| public | No authentication (sign-in, health checks). |
A route that declares nothing is refused with 403 and code: "route_not_declared". A healthy build has none; GET /api/iam/engine/stats lists any it finds.
The settings you maintain
| Setting | Where you change it | What it does |
|---|---|---|
| Workspace role | IAM center → Principals, a person's Change role (owner, admin, project admin, user) | Sets the default level of every service. |
| Own service permissions | IAM center → Principals, a person's Edit access | Replaces the role default for that service. It may lower the default as well as raise it. |
| Group grants | IAM center → Principals → Groups, a group's workspace role and service permissions | Raises the level of every member of the group. A group can only raise. |
| Project member permissions | Settings → Projects, a project's Members, Project service permissions | Caps what a member can do inside that project. It can only lower. See Project permissions. |
| API token scope | Settings → API Tokens (your own tokens), or IAM center → Principals → API tokens (other people's, for owners and admins) | Caps what the token can do. See API tokens. |
Levels
| Level | Meaning |
|---|---|
none | No access. |
read | List and view (GET). |
write | Create, change, delete and run (POST, PUT, PATCH, DELETE). |
admin | Manage. On an administration service every change needs admin. |
| Role | Normal services | Administration services |
|---|---|---|
owner | admin | admin |
admin | admin | admin |
project_admin, user | write | none |
The administration services are automations, members, providers, config, license, audit, gpu-fleet, sandbox, cluster, sso, ldap, webhooks, portals, resources and iam. A person gets one of them only through an explicit service permission or a group grant. Project admins get no extra access to them: to let a project admin manage, say, webhooks, grant that person or their group the webhooks service.
How the settings combine
workspace level = highest of ( own level, the grant of each of the person's groups )
effective level = lowest of ( workspace level,
token scope - API tokens only,
project level - members who are not owners or admins )- People. The workspace level is the highest of the person's own level and each group's grant. In a project, the project level can only lower it.
- API tokens. A token starts from its owner's workspace level, including the owner's group grants, is capped by its scope, and is then limited by the project level of its project (a token without a project runs in the workspace's default project).
- Never limited by a project. Owners, admins, and members who are admin through a group.
Project permissions
A project member (a person assigned to the project, or a group assigned to it) can carry a level per service. On the Project service permissions screen each service shows the workspace level, the level for this project and the result:
| Choice | Effect in this project |
|---|---|
| Inherit | Nothing is set for the service. The workspace level applies. |
| No access | The member cannot use the service here. |
| Read, Write, Admin | The member is capped at that level here. |
A project level never raises access: the lower of the workspace level and the project level applies. Inherit and No access are different things; Inherit is the default and means "no opinion".
When a person reaches a project several ways (their own assignment and the assignments of their groups), the highest level any of them names for a service wins, so a group assignment with Read lifts a personal No access.
What changed for older assignments
Earlier releases stored these levels and showed them in the member screens, but no gate read them, and the screen displayed every service nobody had set as "None". Applying every stored none literally on the first request would cut people off from services nobody meant to restrict. So:
- The first time the engine decides a request in a workspace, it records that moment once (the activation instant, a small
iam_metadocument). - An explicit No access in an assignment that was last saved before the activation instant is read as Inherit.
- Read, Write and Admin entries always apply.
- Assignments saved after the activation instant apply in full, including No access: the screen saves it deliberately now.
One edge case
The rule looks at when the assignment was last saved, and any save counts, also an unrelated one such as changing the member's project role. After that save an old No access in the same assignment starts to apply. Review old assignments after the upgrade: set the services you really want blocked to No access and the rest to Inherit. The preflight report lists them under "Deferred".
API tokens
An API token acts as its owner, with these refinements:
- It takes the owner's group grants too. (Releases before the engine saw only the owner's own workspace level.)
- Its scope is a cap: a service that is not in a scoped token's scope resolves to
none;{}is a scope that allows nothing; no scope means the token inherits the owner unchanged. A scope can only narrow, never widen. - It runs in its project, so the owner's project permissions in that project limit it. A token without a project runs in the workspace's default project.
- It never reaches beyond its project: a question that is about the workspace itself, outside any project (for example, whether a tenant-wide webhook endpoint is in reach), is always answered "no" for a token, whoever owns it.
Expiry rules and IP allowlists are part of Authentication. The tenant-wide metrics export (GET /api/metrics) refuses a token that carries a service scope, because a per-service cap cannot be honoured on an export that spans every module: use an unscoped token for the scraper.
An application can also let its tokens act for the application's own signed-in users instead of for the token's owner: see Acting for a user.
The IAM center
Settings → IAM center gathers the tools. Viewing needs read on the iam service (shown as Authorization Engine in permission lists) and changing needs admin; owners and admins have both.
| Tab | What it is for |
|---|---|
| Overview | Engine status, policy counts and the latest denials, and anything that needs attention: custom statements that could not be applied, routes without a declaration, times authorization was unavailable. |
| Policies | The built-in and custom policies: create, edit, enable, disable, preview. |
| Principals | Every person and API token with their effective level per service and where each level comes from (role, direct grant, group, token scope, project limit, policy). A person's drawer also shows their recent Activity; people of host applications carry an External badge. |
| Access check | "Can this person or token do this, and which rule decides?" and the lookup of a decision id. |
| Audit | Denials and policy changes, with CSV export. |
| Limits | Usage and spending limits for groups, projects and agent runs. |
| Settings | The workspace's API token rules: a maximum lifetime and whether an expiry is required. |
Built-in policies
Twenty-two policies ship with the engine. They are the same in every workspace, cannot be edited or removed, and are listed under Built-in on the Policies tab of the IAM center.
| Policy | What it does |
|---|---|
managed:rbac:user-read, user-write, user-admin | A signed-in person may read, write or administer a service when their effective level reaches it. A change on an administration service needs admin. |
managed:rbac:token-read, token-write, token-admin | The same for an API token, from its owner's level and the token's scope. |
managed:boundary:token-cap-read, -write, -admin | A scoped token is denied what its scope does not name. No custom allow can exceed it. |
managed:boundary:project-read, -write, -admin | A service that the active project limits is denied above the project level. No custom allow can exceed it. |
managed:portal:use, managed:portal:agent | A person on a portal's access list (or in a group on it, or anyone when the portal is open to the workspace) may open the portal and run its agents. See Portal access boundaries. |
managed:portal:use-boundary, managed:portal:agent-boundary | Nobody else may, whatever their role or any allow rule says. Custom deny rules still apply on top. The exceptions are a workspace owner or admin in a marked test session and, for a portal that takes every verified embedded person, someone who arrived through its embed. |
managed:portal:network-boundary, managed:portal:agent-network-boundary | A portal that lists the networks it may be used from is refused to every address outside them (opening it, running its agents, answering its approvals). Portals that list none are not affected. |
managed:portal:test-use, managed:portal:test-agent | A workspace owner or admin may open a portal and run its agents in a marked test session although the access list does not name them. |
managed:agent:approve, managed:agent:approve-token | A person (or a token, on behalf of its owner) may approve a tool call of an agent session when they started it, or when the agent's Who can answer setting accepts them. The generic Write permits leave this one action out, so this rule is what appoints; your own allow rules can appoint more approvers. See Who can approve tool calls. |
The simple settings stay the single place to change what people can do; the built-in policies only translate them. Nothing is stored per person or per group in a policy.
Custom policies
Use a custom policy for what the simple settings cannot say. A policy is enabled or disabled, and Allow or Deny; a deny always wins and an allow can never go beyond a token's scope or a project's limits. See Custom policies for the guided editor, Cedar text, examples, limits and the API.
Refusals, decision ids and the Access check
Every refusal carries a decision id so that the person who was refused and the person who investigates talk about the same event. Paste it into IAM center → Access check → Look up a denied request, or call GET /api/iam/decisions/{decisionId}. See Troubleshooting and FAQ for the response shapes, every refusal code and how to replay a decision.
If the engine cannot decide a request, the request is refused with 503 authorization_unavailable, never allowed and never decided by some other rule set. The server also refuses to start without a working engine, and GET /api/health/ready has an authorization-engine check (ok, degraded or down).
Owner safety
The workspace owner's own signed-in session can always reach the iam service, whatever custom policies say and even when the engine is down, so an owner can always repair the policies: sign in as the owner, then disable or delete the rule that locks people out. This is a promise about the owner's session only. An API token that belongs to the owner is an ordinary principal, and a policy can restrict it.
Client address and TRUSTED_PROXIES
Token IP allowlists, the ip condition of policies and a portal's network restriction need an address the server can vouch for.
TRUSTED_PROXIESset (comma-separated IPs or CIDRs of your reverse proxies or load balancers): the address is the one Fastify resolves through those proxies. The forwarded address counts only when the connection comes from a listed proxy, and it is the entry the proxy itself appended; anything a client wrote to its left is ignored.TRUSTED_PROXIESunset (the default): forwarded headers are not used for authorization at all. The connection address is matched, so a caller cannot claim an allowed address. Behind a proxy every caller then looks like the proxy and an IP rule never matches.
Behind a reverse proxy or load balancer, set it:
TRUSTED_PROXIES=10.0.0.0/8,172.16.0.0/12The proxy must append the client address to X-Forwarded-For (nginx: proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;). X-Real-IP and Forwarded are never read directly. The IAM center and the token forms warn while it is unset.
How fresh is a decision
| What changed | Takes effect |
|---|---|
| A person's role, own permissions, group grants (sessions) | On the next request: they are read on every request. |
| A custom policy | At once on the server that saved it, within 5 seconds on the others. |
| Project assignments, and group membership as custom policies and API tokens see it | At once on the server that handled the change; within 15 seconds on the others. |
| A token's scope, expiry or IP allowlist | On the next call on the server that handled the change; within 60 seconds on the others. |
| A token's acting for users setup | At once on the server that saved it; within 10 seconds on the others. The account a person resolves to is read again on every call. |
What policies do not govern
- Background work. Scheduled jobs (inference polling, alert evaluation, analysis and red-team runs, knowledge-base ingestion) run without a principal. A policy restricts the person who starts something, not a job that was already scheduled.
- Realtime connections. A WebSocket is decided once, when it connects.
- Public and self-authenticated routes, by design.
- Individual resources. The request gates decide on services. A rule about one agent or one model is accepted by the Access check and the preview, but nothing asks it at the gate yet, so the editor refuses a deny of that kind. The exceptions are portals (opening one and running an agent through it are decided per portal and per agent), the session actions of an agent, and the Files bucket an agent keeps its session files in.
API
The IAM API is part of the dashboard API: it authenticates with the session cookie, not with an API token. Its service is iam: GET needs read, every change needs admin.
| Endpoint | Purpose |
|---|---|
GET /api/iam/catalog | Services, actions, resource types, context attributes and channels. Each action says where a real request is decided on it (enforcedIn: dashboard and api for a service action and for the session actions, portal for portal.use, agent.invoke and agent.approve where portals exist); an action without it is only evaluated by the Access check. |
GET /api/iam/policies, GET /api/iam/policies/{policyId} | Built-in and custom policies. |
POST /api/iam/policies, PUT /api/iam/policies/{policyId}, DELETE /api/iam/policies/{policyId} | Create, change (also enable and disable) and delete a custom policy. |
POST /api/iam/policies/compile, POST /api/iam/policies/preview | Compile a draft, and see who it would affect. Read-only. |
POST /api/iam/simulate | The Access check. Read-only. See Troubleshooting and FAQ. |
GET /api/iam/decisions/{decisionId} | A refusal the caller saw, as an access check. |
GET /api/iam/principals, GET /api/iam/principals/{type}/{id} | People and tokens with their effective levels. |
GET /api/iam/principals/user/{id}/activity | A person's recent activity: usage by service over days (default 30, at most 90) and the latest limit audit rows they are the subject of. |
GET /api/tokens/{id}/delegation, PUT /api/tokens/{id}/delegation, DELETE /api/tokens/{id}/delegation | The acting-for-users setup of an API token. Owners and admins only, never upward. |
GET /api/iam/audit, GET /api/iam/audit/export | Denials and policy changes (kind=denials or changes). |
GET /api/iam/settings, PUT /api/iam/settings | Tenant API token rules. |
GET /api/iam/engine/stats | Engine health, decision counters, the workspace's policy set, undeclared routes. |
GET /api/auth/session | Besides the user, effectivePermissions (a level per service) and effectiveProjectId, which the dashboard menu follows. |
A policy is { policyId, name, description, effect, enabled, spec, cedar, statementCount, ... }. Send name, description, enabled and either spec or cedar. Errors are { error, code, details? }; code: "validation" carries details with a message and, for Cedar text, a line and col.
What's new
- One engine decides every request, in every workspace, with no switch to turn on. Refusals carry a decision id and an
X-Decision-Idheader, and a route that declares no authorization is refused. - Project permissions now apply, API tokens include their owner's group grants, and group project assignments open projects. See Upgrading to the policy engine for who is affected.
- New administration services:
portals,resources,iamandwebhooks. - Agent sessions belong to the person who started them: approvals, viewing and acting on other people's sessions and the Files bucket of session files are decided by the engine.
- Acting for a user (verified end-user identity for the client API) and external users.
- Portal network restriction, test sessions and "View as" (Enterprise).

