Scoped token issuance and permission enforcement for relayfile. Control exactly what each agent can read, write, and access.
Agents need access to files. They shouldn't have access to all files. Relayauth issues scoped JWT tokens where the VFS paths are the permission boundaries:
# Code review agent: read PRs, write only reviews
relayfile:fs:read:/github/repos/acme/api/pulls/*
relayfile:fs:write:/github/repos/acme/api/pulls/*/reviews/*
# Support agent: Slack support channel only
relayfile:fs:read:/slack/channels/support/*
relayfile:fs:write:/slack/channels/support/messages/*
# Notion reader: specific pages, read-only
relayfile:fs:read:/notion/pages/product-roadmap/*
relayfile:fs:read:/notion/pages/eng-specs/*No separate ACL config. The filesystem paths are the permissions.
npm install @relayauth/sdkimport { TokenVerifier } from "@relayauth/core";
const verifier = new TokenVerifier({ signingKey: process.env.SIGNING_KEY! });
const claims = await verifier.verify(token);
// claims.scopes → ["relayfile:fs:read:/github/*", "relayfile:fs:write:/github/*/reviews/*"]import { ScopeChecker } from "@relayauth/core";
const checker = new ScopeChecker(claims.scopes);
checker.check("relayfile:fs:read:/github/repos/acme/api/pulls/42/metadata.json");
// ✅ allowed
checker.check("relayfile:fs:write:/slack/channels/general/messages/reply.json");
// ❌ denied — agent only has GitHub accessSIGNING_KEY=my-secret \
RELAYAUTH_SUB=review-agent \
RELAYAUTH_SCOPES_JSON='["relayfile:fs:read:/github/*", "relayfile:fs:write:/github/*/reviews/*"]' \
./scripts/generate-dev-token.shnpm install
SIGNING_KEY=my-secret npm run startScopes follow plane:resource:action:path:
| Segment | Values | Example |
|---|---|---|
| plane | relayfile, relaycast, cloud, relayauth, * |
relayfile |
| resource | fs, ops, admin, * |
fs |
| action | read, write, create, delete, manage, * |
read |
| path | VFS path with wildcard support | /github/repos/acme/* |
manage implies read + write + create + delete.
Path matching: /github/repos/acme/* matches any file under that prefix.
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ Agent │────▶│ relayfile │────▶│ relayauth │
│ │ │ (VFS) │ │ (verify + │
│ read/write │ │ │ │ enforce) │
│ files │ │ checks token│ │ │
└──────────────┘ │ on every │ │ scopes map │
│ request │ │ to VFS paths│
└──────────────┘ └──────────────┘
- Agent sends request with JWT token to relayfile
- Relayfile passes the token to relayauth for verification
- Relayauth checks the token's scopes against the requested path
- If allowed, relayfile serves the file. If not, 403.
Place .relayfile.acl files in any directory to set permissions that inherit downward:
{
"semantics": {
"permissions": [
"scope:relayfile:fs:read:*",
"deny:agent:untrusted-bot"
]
}
}Rules:
scope:<scope>— allow if token has matching scopeagent:<name>— allow if JWTagent_namematchesdeny:scope:<scope>/deny:agent:<name>— explicit deny (overrides allow)- Child rules append to parent rules (inheritance)
Relayauth supports config files for managing agents, roles, and ACLs declaratively:
# relay.config.yaml
agents:
review-bot:
roles: [reviewer]
support-bot:
roles: [support]
roles:
reviewer:
scopes:
- relayfile:fs:read:/github/*
- relayfile:fs:write:/github/*/reviews/*
support:
scopes:
- relayfile:fs:read:/slack/channels/support/*
- relayfile:fs:write:/slack/channels/support/messages/*
acl:
- path: /github
rules:
- scope:relayfile:fs:read:*
- path: /slack/channels/support
rules:
- role:supportRelayfile Cloud manages token issuance, agent permissions, and scope enforcement. No self-hosting required.
npm install
npx turbo build
npx turbo testMIT