Identity and permissions for agents
Understand what your Platform credential can do, why a call was denied, and how to give automation its own durable Bot identity. This page extends https://app.tokay.io/llms.txt. Act only on an explicit user request or named readiness action.
Last updated
AI agent? Start with llms.txt.
The authority model
- You act as a durable Person or Bot. An AI agent is the tool, not another identity that carries authority.
- Current Workspace, Project, and repository memberships define which resources the principal can reach.
- Every API, MCP, Git HTTPS, and SSH credential carries explicit action grants that can only narrow that membership authority. Browser sessions remain the recovery and account management surface.
- API and MCP use distinct token kinds and exact audiences. API credentials work at GraphQL and API REST. MCP credentials work only at the official MCP endpoint. Git credentials work only for Git transport.
- Platform and Tokay Access credentials never cross. A
tokay_machine_...credential opens one deployed app Project and cannot manage Tokay. - Revocation and membership changes are checked on every protected Platform operation.
Create credentials only with explicit grants
Each destination has its own creation grant.
| Grant | May issue |
|---|---|
CREDENTIAL_CREATE_API |
JWT for the API audience |
CREDENTIAL_CREATE_MCP |
JWT for the MCP audience |
CREDENTIAL_CREATE_GIT |
Git HTTPS password or SSH public key registration |
Creation grants are never implied or preselected. For ordinary creation, a bearer creates a narrower credential for the same Person or Bot. The new credential cannot carry a creation grant. Git credentials cannot create anything.
API and MCP leaves default to one hour, must expire within 24 hours, and cannot outlive a finite root. Git HTTPS and SSH leaves have optional expiry instead. They may be unbounded beneath an unbounded root, while a finite root caps them at its own expiry. All leaves die when their root and its lineage are revoked.
Creating a credential for another destination requires the exact creation grant and explicit acknowledgement. In particular, an API credential created from MCP works directly outside MCP tool restrictions and review flows. People and Bots can use either Git encoding.
Git grants may be wildcard, pinned to one Workspace, or pinned to one repository. A grant must name at most one target. SSH public key, grants, owner, lineage, and access expiry are immutable after registration. renamePlatformCredential changes only the label.
Connect an outside client with OAuth
Use Platform OAuth when a CLI, desktop agent, or MCP client needs approval without copying a token.
| Destination | Resource |
|---|---|
| GraphQL and API REST | https://api.tokay.io |
| Official Tokay MCP | https://mcp.tokay.io/mcp |
Discovery starts at the resource metadata endpoint for protected resources. The client publishes an HTTPS Client ID Metadata Document and uses authorization code with S256 PKCE. Scope names must match the exact PermissionActionType casing.
Consent chooses whether the connection acts as the approving Person or an authorized Bot. Choosing a Bot records the Person's permission to use that Bot. Removing that permission or the Person's Workspace membership disconnects the connection. A later admin demotion does not silently remove the permission.
Every authorization creates an independent connection. Platform OAuth returns no refresh token or expires_in. The connection stays active until disconnected, revoked, or its principal loses authority. OAuth roots do not rotate. Disconnect and complete OAuth again. API and MCP credentials cannot be exchanged.
Create a Bot identity
Creating a Bot establishes identity and memberships only.
mutation CreateBot($workspace: ID!, $project: ID!) {
createBot(input: {
workspace: $workspace
displayName: "deploy-bot"
projectMemberships: [{ project: $project, role: MEMBER }]
repoMemberships: []
}) {
bot { id principal { id displayName } }
}
}
The Bot cannot authenticate until an authorized Person separately provisions a root credential.
mutation ProvisionBot($bot: ID!) {
provisionBotCredential(input: {
bot: $bot
label: "deploy-bot API"
credentialKind: API_JWT
grants: [
{ action: PROJECT_STATUS }
{ action: PROJECT_LOGS }
{ action: PROJECT_DEPLOY }
]
acknowledgeSurvival: true
acknowledgeCrossDestination: false
}) {
platformCredentialCreation {
jwt
credentialKind
destination
isLeaf
expiresAt
}
}
}
jwt is shown once. Provisioning creates a durable handoff. The Bot root survives the issuing credential's expiry, revocation, and OAuth disconnect. The Bot's memberships remain its resource boundary.
Create a narrower worker credential
An API or MCP root with the exact target creation grant can call issuePlatformCredential. The child cannot contain CREDENTIAL_CREATE_* and cannot exceed the root's ordinary grants.
mutation IssueLeaf {
issuePlatformCredential(input: {
label: "one deploy"
credentialKind: API_JWT
grants: [{ action: PROJECT_STATUS }, { action: PROJECT_DEPLOY }]
acknowledgeCrossDestination: true
}) {
result { jwt destination isLeaf expiresAt }
}
}
At MCP, use the dedicated reviewed tools issue_platform_credential and provision_bot_credential. The first call returns exact impact and a ten minute receipt. Repeating the unchanged request with that receipt executes once and returns the credential once.
Each Person or Bot has separate limits of 100 API roots, 100 MCP roots, and 100 independent Git credentials total across HTTPS and SSH. Each API/MCP root has its own 100-leaf counter across API, MCP, Git HTTPS, and SSH leaves, so a leaf never consumes a root slot or another root's capacity.
Rotate a manual API or MCP root
A live API or MCP root that was not created through OAuth can replace only itself. Rotation preserves its principal, label, destination, grants, and root position, then atomically revokes the predecessor and every direct leaf. Omitting expiresAt preserves the old expiry. A finite root may be shortened but not extended.
mutation RotateRoot {
rotatePlatformCredential(input: {}) {
platformCredentialCreation { jwt credentialKind destination expiresAt }
}
}
The successor JWT appears once. If the committed response is lost, the old root is already dead and the successor cannot be recovered. MCP callers use the reviewed rotate_platform_credential tool, which previews the exact revoked lineage and independently surviving credentials. OAuth roots must disconnect and authorize again.
Register an SSH Git credential
An API or MCP root with CREDENTIAL_CREATE_GIT can register a narrower SSH credential for the same Person or Bot through the reviewed register_ssh_key MCP tool or registerSshKey GraphQL mutation. Supply explicit Git grants and acknowledge the Git destination. The registration may have an access expiry and is revoked with its root. The key authenticates Git only and is never a Workspace VM login credential.
mutation RegisterKey($workspace: ID!) {
registerSshKey(input: {
label: "deploy workstation"
publicKey: "ssh-ed25519 AAAA..."
grants: [
{ action: REPO_READ, workspace: $workspace }
{ action: REPO_WRITE, workspace: $workspace }
]
acknowledgeCrossDestination: true
}) {
platformCredential {
id
label
sshFingerprint
expiresAt
grants(first: 10) { nodes { action workspace { id name } repo { id name } } }
}
}
}
Use provisionBotSshKey or the reviewed provision_bot_ssh_key tool when a Person deliberately creates an independent SSH credential for a Bot. That handoff requires authority to manage the Bot and acknowledgement that it survives the provisioner's credential.
Revocation
Revoke the smallest credential set that contains the problem.
- Self revokes one credential without replacement.
- Lineage revokes a root and the direct leaves created for the same Person or Bot.
- Revoking a Bot root always includes its leaves.
- Passive expiry never sweeps descendants.
A lineage may have provisioned independent credentials for another principal. Revocation preview returns one review set and lets the user explicitly include any credential they can currently manage. Selected API/MCP roots bring their direct leaves. Routine revocation never crosses that boundary silently.
At MCP, use the reviewed revoke_platform_credential tool. The first call shows the exact Self or Lineage targets and independent review set. Show that impact to the user. Repeat the unchanged request with its receipt and the explicitly selected credentials only after they approve it. Generic GraphQL mutation access cannot revoke or rotate credentials.
Grant actions
Grants use exact PermissionActionType names. Common actions include:
| Action | Covers |
|---|---|
WORKSPACE_READ |
Discover and read Workspace context |
WORKSPACE_CREATE_PROJECT, WORKSPACE_CREATE_REPO |
Create Projects and repositories |
WORKSPACE_MANAGE_ACCESS |
Members, Bots, operators, and Workspace connections |
PROJECT_STATUS |
Project and Service state |
PROJECT_LOGS |
Logs and runtime output |
PROJECT_QUERY, PROJECT_EXPORT |
Managed data queries and exports |
PROJECT_WRITE, PROJECT_DEPLOY |
Configure and deploy Services |
PROJECT_WRITE_SECRETS |
Set Secret values without reading them back |
PROJECT_MANAGE_ACCESS |
Project and Service access, public paths, Visitors, and Machines |
PROJECT_DESTROY |
Permanent and destructive Project operations |
REPO_READ, REPO_WRITE, REPO_MANAGE_ACCESS, REPO_DESTROY |
Repository equivalents |
REPO_READ includes committed source and readable Project Config for API/MCP credentials. Git grants pinned to a Workspace or repository authorize only Git transport. Secrets remain write only.
Read a denial
A denied call names the missing action and target, for example Not authorized for PROJECT_DEPLOY on SERVICE <id>. Report that exact action and target. Do not retry unchanged or ask for broad authority when one named grant is enough.
Credential hygiene
- Send API credentials as
Authorization: Bearer <token>only to the API resource. - Never write a credential into source, Config, Secrets, task commands, or logs.
- Prefer one distinct leaf per worker or subagent instead of sharing a bearer. This preserves attribution and independent revocation.
- Discard a credential after
401 invalid_token. OAuth connections reauthorize rather than refresh. - Remove a Bot only when you intend to end the entire identity, memberships, connections, operator permissions, roots, and leaves.