Access control

Access rules decide who can reach what. Every rule is enforced at the hub, before a request ever touches your box. The policy is default-deny: no matching allow rule means the request is denied. You manage rules on the dashboard's Access page (admin only).

How a request is checked

A caller presents a finch_ key (see Keys & auth). Two gates must both pass:

  1. Key scope. The key must be scoped to all services or explicitly list the target service. This is the coarse per-key gate.
  2. Access rules. At least one allow rule must match: its source must match the key's identity, and its destination must match the target service. No match means a 403, and the request never reaches your box.

A key's identity for rule matching is the key itself (by label or id), the user who owns it, and any groups that user or key belongs to.

One exception: a service whose auth is set to public skips both gates. It needs no key at all, so access rules do not apply to it.

Rules: source may reach destinations

A rule grants one source access to one or more destinations. You build rules in the dashboard as "source may reach destinations".

SideTypesMatches
Sourceuser, group, keyThe identity presenting the key: a specific key, a user (covers every key that user owns), or a group.
Destinationservice, tag, group, allThe target: one service by id, every service carrying a tag, every service in a group, or everything.

The dashboard's rule builder offers tag and group destinations. service and all exist in the rule model (the seeded owner rule uses all) but are not choices in the builder.

Tags are the practical unit. Tag your services on the Services page, then grant by tag: a rule like key:crawler may reach tag:scraping keeps working as you add and remove services, with no rule edits.

The owner rule

Every tenant is seeded with one locked rule: the owner may reach all services. It shows in the rule list as admin · locked and cannot be removed, so the owner can never lock themselves out. Everyone else is denied until you add an explicit allow rule.

The generated policy

The Access page has a Raw policy tab showing policy.json, generated from your rules. It is the source of truth at the door: what you see there is exactly what the hub enforces.

{
  "tagOwners": { "tag:scraping": ["you@finch"] },
  "acls": [
    { "action": "accept", "src": ["you@finch"], "dst": ["*"] },
    { "action": "accept", "src": ["key:crawler"], "dst": ["tag:scraping"] }
  ]
}

One key per agent

The common setup: you run several MCP services and several agents, and each agent should reach only some of them. Mint one key per agent, scope it to the services that agent needs, and add a rule for it.

# a key for the research agent, scoped to one service
finch keys mint research-agent --service scraper

# revoke it later; access stops immediately
finch keys revoke <id>

Then in the dashboard, grant key:research-agent access to the tag (or group) it should reach. Different users and agents get different views of your fleet, and revoking one key cuts off exactly one caller.

Scope is a floor, not a grant. A key scoped to a service still needs a matching allow rule. The owner's locked rule is why keys you mint for yourself work out of the box: they match as user: you.

Users & roles

The dashboard's Users page (admin) lists everyone in your tenant. Invite a teammate by email; they get an email to join. Roles decide who can administer: who can approve boxes, edit access rules, and manage keys.

RoleCan do
OwnerEverything. Cannot be removed or demoted.
AdminAdminister the tenant: boxes, access rules, keys, users.
MemberUse the services they have been granted access to.

Users appear as rule sources, so "user may reach tag" is how you give a teammate access to a slice of your fleet.