Skip to content

Forgeplane service accounts and API keys

A service account is a non-human Forgeplane identity for CI/CD pipelines, automation scripts, and external integrations. It authenticates with API keys rather than passwords or browser sessions and uses the same platform permissions model as a human user.

Use a service account when an automated process needs a stable owner, an explicit role, key rotation, and auditable API access. Use the least-privileged role that covers the process; do not reuse a human user’s personal key for automation.

Every service account has exactly one owner: a user or a team. Account operations use the canonical authorization catalog and recheck current state before mutations. A service account is an independent Principal: the owner’s grants never transfer to it, and it cannot act as its owning user.

Owner Field Authorization
User owner_user_id The authenticated user must be the owner and have service_account:read for reads or service_account:manage for mutations. There is no platform-admin ownership bypass.
Team owner_team_id Requires the matching service-account permission and the exact team’s owner role, or an explicit platform admin grant. Team admin membership is not sufficient.

Exactly one owner field is required when creating the account. The fields are mutually exclusive. The platform admin, maintainer, and operator roles carry service-account permissions; requester does not. An ownership change requires authorization for the existing account and creation in the destination scope. It does not permit arbitrary user-to-user transfers.

Lists contain only authorized accounts. Missing and inaccessible named accounts share a private denial rather than distinct not-found responses.

In the current release, run-creating automation must use a user-owned service account. A team-owned service account cannot derive the user-level created_by required by template-run creation. The owner user must have the required organization and team access. Do not work around this limit by supplying an arbitrary user UUID.

The service account’s own role determines its platform permissions. Team-role assignments apply only to its owner team; explicit platform-administrator grants in the catalog still apply. Ownership does not copy the user’s permissions or memberships. Disabling a user owner does not disable the account. Maintainers and operators cannot assign the admin or operator role to service accounts.

Review Permissions and roles before assigning requester, maintainer, or operator. A requester can create a run only when the matching internal execution plan is already cached; it cannot approve or cancel runs or create that plan. An authorized maintainer must materialize the plan by creating the first run for the exact project, template version, and operation. Maintainers can also manage delivery operations and approvals; operators additionally have run-record deletion permission.

A service account requires a name, description, role, and owner. Set FORGEPLANE_URL to the trusted coordinator’s HTTPS origin and supply OWNER_API_KEY securely. For a user-owned account, use that user’s credential and user ID:

Terminal window
curl --fail-with-body --silent --show-error \
-X POST "$FORGEPLANE_URL/api/v1/service-accounts" \
-H "X-API-Key: $OWNER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "ci-deploy",
"description": "CI/CD pipeline for production deployments",
"role": "maintainer",
"owner_user_id": "user-uuid-here"
}'

For shared automation whose operations do not require user attribution, replace owner_user_id with an authorized owner_team_id. Team-owned accounts cannot use the template-run creation path described above. Use the runtime API contract for the exact schema and permissions in the deployed release.

Each service account can have one or more API keys. A key is returned in full only at creation time; store it in the CI/CD system’s secret store because Forgeplane cannot retrieve the value later.

Keys expose only an identification prefix for administration, such as fpk_abc1.... A key may have an expiration date. Expired keys are rejected during authentication. Keys without an expiration remain valid until revoked.

Listing, creating, and revoking keys require the parent service account’s manage operation. API credentials are subresources, not separate v1 can-i resources. The credential ID must belong to the account being managed.

Set SERVICE_ACCOUNT_ID to the ID returned at account creation. Create a key with a name and optional expiration:

Terminal window
curl --fail-with-body --silent --show-error \
-X POST "$FORGEPLANE_URL/api/v1/service-accounts/$SERVICE_ACCOUNT_ID/api-keys" \
-H "X-API-Key: $OWNER_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "github-actions",
"expires_at": "2027-01-01T00:00:00Z"
}'

For a controlled rotation:

  1. create a new key;
  2. store it in the consuming system;
  3. switch the pipeline or integration to the new key;
  4. confirm the new key is used; and
  5. revoke the old key.

Both keys can be valid during the transition. Use the service-account ID and the credential ID returned by the key-list operation. Revocation records a reason in the audit log:

Terminal window
curl --fail-with-body --silent --show-error \
-X POST \
"$FORGEPLANE_URL/api/v1/service-accounts/$SERVICE_ACCOUNT_ID/api-keys/revoke?credential_id=$CREDENTIAL_ID" \
-H "X-API-Key: $OWNER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"reason":"Scheduled rotation"}'

A disabled service account rejects API requests without deleting its configuration or keys. Authorized owners can still view, update, delete, re-enable, and manage keys for the disabled account. Re-enabling restores access only through credentials that remain valid; it does not revive expired or revoked keys.

Authentication and mutation admission reject revoked, expired, deleted, malformed, or orphaned credentials and principal assignments. Mutations recheck current state under database locks, including concurrent credential revocation.

Disabling, demoting, or deleting the final effective platform-administrator Principal returns 409 Conflict. An enabled service account with a valid admin assignment counts even when all its keys are expired or revoked. Credential validity and administrator assignment are separate.

Forgeplane records last_used_at and last_used_ip for each API key. Use these fields to identify stale keys or unexpected use, then inspect the audit log for account, role, key, enable/disable, and authentication events.