A service account is a bot identity inside an organization. Use one when you want an AI agent, automation, or long-running script to call airlock without being tied to a specific human user — for example, a CI job or a background agent.
Service accounts authenticate with service tokens, not OAuth. They are granted access to specific integrations, skills, and agents the same way a user or group is.
When to use a service account
- A scheduled job that needs to call MCP tools on its own schedule.
- A self-hosted agent that should keep working when no human is signed in.
- A CI/CD pipeline that calls airlock from a build runner.
- An agent runtime that needs persistent, non-interactive access.
If a real person is driving the calls, use their normal user sign-in instead.
Creating a service account
Service accounts are an admin-only feature. Open Service Accounts from the admin section of the sidebar (or go directly to /service-accounts) in the Control Room.
- Click Create service account — this opens a separate page
- Give it a descriptive name (e.g.
nightly-research-bot) - Optionally add a description so other admins know what it's for
- Click Create service account
The new service account is created in ACTIVE status, scoped to your organization. It has no credentials yet — you mint those separately in the next step — and, importantly, no access to anything until you grant it some (see Access grants).
Issuing a service token
Service tokens are the credentials a service account uses to call MCP. They look like this:
alk_svc_<random>
The alk_svc_ prefix lets you recognise an airlock service token in logs and dashboards.
- Open the service account's detail page
- Enter a token name (e.g.
github-actions) - Click Create token
- Copy the token immediately — airlock only ever shows the full value once
Note: The Control Room always issues tokens with the default 1-year lifetime. To set a custom lifetime (anywhere between 1 hour and 1 year), create the token via the API and pass
expiresInSeconds— there is no lifetime picker in the UI.
After that, only the prefix (alk_svc_XXXXXXXX) is visible in the Control Room. The full token is hashed with SHA-256 before storage; even airlock admins can't recover it.
Expired tokens are cleaned up automatically (DynamoDB TTL); revoked tokens stay visible in the audit trail but stop authenticating immediately.
Org-wide vs service-account tokens
There are two flavours of service token:
Org-wide tokens default to full admin access. Unlike a service-account token — which starts with access to nothing — a token created at
POST /v1/orgs/:orgSlug/service-tokenswith noaccessRolegets every integration and every tool, unfiltered. PassaccessRole: "MEMBER"to scope it down, or better, use a service-account token instead.
| Flavour | Endpoint | When to use |
|---|---|---|
| Service-account token | POST /v1/orgs/:orgSlug/service-accounts/:id/tokens | The typical case — token is scoped to a specific bot identity, inherits its access grants, and shows up under that account in audit logs. |
| Org-wide service token | POST /v1/orgs/:orgSlug/service-tokens | A token not tied to any service account. It defaults to full organization-admin access — every integration and every tool, with no access filtering. Pass accessRole: "MEMBER" on creation to scope it to ordinary member permissions instead. Use it only for one-off scripts or migrations that genuinely need org-wide reach. |
Prefer service-account tokens whenever possible — they make audit trails and access scoping much cleaner.
Using a service token
Store the token in an environment variable (or your platform's secret manager) and pass it as a bearer token on the MCP HTTP endpoint:
export AIRLOCK_SERVICE_TOKEN="<your alk_svc_ token>"
curl https://mcp.air-lock.ai/org/<your-org-slug> \
-H "Authorization: Bearer $AIRLOCK_SERVICE_TOKEN" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/list","id":1}'The same token works for every MCP method the service account is authorised to use — initialize, tools/list, tools/call, and the airlock meta-tools.
Access grants
Service accounts are granted access to specific resources — integrations, skills, and agents — rather than to a bundle.
A service account starts with no access at all. Unlike human members, it never inherits an integration's open default. It still sees airlock's meta-tools, but
list_servicesandsearch_toolscome back empty until you grant it something.
In the Control Room, open the service account's detail page and use the Access section to grant it the integrations, skills, and agents it needs. For an integration you can grant every tool or select individual tools. Grants take effect on the service account's next tools/list call.
Attribution: Tracking Who Triggered Agent Runs
When an agent authenticates with a service account token, the caller can assert which human triggered the run, so agent activity is attributable to a person rather than only the bot identity.
Why this matters
A service token (alk_svc_...) is shared by many people — the agent runtime might be called by Alice's workflow one minute and Bob's the next. The X-Airlock-On-Behalf-Of header lets the caller assert who is behind each request, so approval screens, audit logs, and agent history show the name of the person who triggered it rather than just the service account.
How to use it
Pass the human's identifier in the X-Airlock-On-Behalf-Of HTTP header when calling MCP:
curl https://mcp.air-lock.ai/org/<your-org-slug> \
-H "Authorization: Bearer $AIRLOCK_SERVICE_TOKEN" \
-H "X-Airlock-On-Behalf-Of: alice@example.com" \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"tools/call","params":{...},"id":1}'The identifier can be an email address or a user profile id. Airlock resolves it best-effort against members of your organization and persists both the raw claim and the resolution result.
Protocol-native fallback: If you cannot set custom HTTP headers, you can pass the claim in the request body under params._meta.onBehalfOf instead. The header takes precedence when both are present.
Security model
- Service-token auth only — This header is accepted only when authenticating with a service account token (
alk_svc_...). Any other authentication mode (user bearer tokens, personal tokens) ignores it completely, so regular user requests behave byte-for-byte as they always have. - Caller-asserted, not verified — The claim is spoofable by design: anyone holding the service token can assert any name, including a colleague's. Airlock resolves it against org members and displays it in the UI, but treats it as attribution metadata only. It never influences policy evaluation, toolset resolution, approval routing, or replay identity — those all still use the service account's own identity.
- Always labeled — Every surface in the Control Room renders the claim with a "(caller-asserted)" marker, so an approver or auditor knows it came from the agent runtime, not from airlock's authentication layer.
Input validation
The claim is trimmed and capped at 128 characters, following the same hygiene as the correlation header. Display-control characters (bidi overrides, zero-width spaces) are stripped, so a crafted claim cannot visually obscure the "caller-asserted" marker.
Where it appears
When you set this header, the airlock UI shows the claim wherever the service account identity appears:
- Agent history (
/history) — the Actor line showsagentX (service account) · on behalf of alice@example.com (caller-asserted) - Pending request details (
/pending-requests) — the expanded row and the full request page both show an "On behalf of … (caller-asserted)" line - Audit logs — request-created events and tool-call events carry the claim in their metadata
If the claim resolves to a member of your organization (by email or profile id), airlock persists the resolution and shows the member's email. If it doesn't resolve — maybe it's a typo, or a member from a different org, or someone not yet in airlock — the raw claim is still stored and displayed.
Credentials for target APIs
A service token authenticates the bot to airlock. It says nothing about the APIs behind your integrations — the service account needs its own credentials for those, exactly like a human user does.
On the service account's detail page, the Credentials section lists every integration you granted it in the Access section:
- For OAuth integrations, click Connect with OAuth and complete the flow.
- For API-key or bearer integrations, paste the token and save.
- Rows marked No credentials required are internal airlock surfaces.
Credentials are stored with the same KMS envelope encryption as user credentials, and only apply to integrations the service account has been granted.
Disabling and revoking
You have two levers, depending on how surgical you want to be:
- Revoke a single token — invalidates that one credential immediately. Other tokens on the same service account keep working.
- Disable the service account — flips its status to
DISABLED. All tokens on the account stop working at once, but the account itself (and its access grants) is preserved so you can re-enable it later.
Disabled accounts can be re-enabled from the same screen; revoked tokens cannot — you'd issue a new one.
Service accounts and the AI Use Policy
If your organization enforces a company AI use policy, service accounts and service tokens are exempt from the signature gate — there is no person to present a policy to, and a bot has no Control Room session in which to sign. Their tool calls are never blocked by the policy gate.
To keep the governance record complete, an admin can record an acknowledgement on behalf of a service account. It is stored against the currently published policy version, permanently, with the admin who recorded it named on the record and an entry in the audit log. Only admins can do this, only for active service accounts in their own organization, and only against the version currently in force — you cannot back-date an acknowledgement to a superseded version.
Security notes
- Tokens are stored hashed (SHA-256); only the prefix is recoverable from storage.
- Treat service tokens like passwords: never commit them to git, prefer your platform's secret manager, and rotate them well before the expiry date.
- All token creation, revocation, and service-account changes are written to the audit log with the admin's identity.
- A revoked or expired token returns
401 Unauthorizedon its next MCP call — agents using it should refresh or fail loudly rather than retrying silently. - Service accounts go through approval workflows just like human users — when a service account calls a tool marked Require Approval, the call pauses as a pending request that an org admin can approve or reject, and the agent can poll
airlock/check_statusto resume once it's decided. Unattended callers should be built to handle aPENDING_APPROVALresponse rather than treating it as an error. - For defense in depth, pair service accounts with an IP allowlist so their tokens only work from the networks you expect. See Network access for the per-organization and per-service-account allowlists.