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:
- Key scope. The key must be scoped to all services or explicitly list the target service. This is the coarse per-key gate.
- 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".
| Side | Types | Matches |
|---|---|---|
| Source | user, group, key | The identity presenting the key: a specific key, a user (covers every key that user owns), or a group. |
| Destination | service, tag, group, all | The 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.
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.
| Role | Can do |
|---|---|
| Owner | Everything. Cannot be removed or demoted. |
| Admin | Administer the tenant: boxes, access rules, keys, users. |
| Member | Use 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.