API keys serve as a way to authenticate applications where individual user identification and authentication are not required. They function as permanent access tokens.
Create an API Key for a Project
You can create a project-specific API key using the GraphQL API:
mutation {
createApiKey(
projectSlug: "my-blog",
description: "User-friendly description of the key",
memberships: [{role: "editor", variables: [{name: "language", values: ["cs"]}]}]
) {
ok
error {
code
}
result {
apiKey {
id
token
identity {
id
}
}
}
}
}
This returns three identifiers:
- API Key ID: Used for disabling this API key later.
- Identity ID: Used to modify the API key's memberships and permissions.
- Token: A bearer token used for authenticating your GraphQL requests.
Create Global API Key
mutation {
createGlobalApiKey(
description: "Global API key description",
roles: ["super_admin", "monitor"]
) {
ok
error {
code
}
result {
apiKey {
id
token
identity {
id
}
}
}
}
}
This also returns three identifiers similar to creating a project-specific API key.
Custom Token Generation
Both createApiKey and createGlobalApiKey support the optional tokenHash parameter. If you provide a SHA-256 hash of the token you wish to use, the API will not generate a new token, and the token field in the response will be empty. This allows you more control over token management but requires you to securely generate and store the original token yourself.
Trusted-proxy API keys
Both createApiKey and createGlobalApiKey accept options.trustForwardedClientInfo: true. An api_key with that flag honors the X-Contember-Client-IP and X-Contember-Client-User-Agent headers from the request, so session tracking, audit logs and Content API userInfo see the real end-user IP/UA rather than the proxy's socket.
This is intended for backend services that proxy user requests. The flag carries a strict security contract on the proxy side — see proxy trust before enabling.
mutation {
createGlobalApiKey(
description: "Backend → Contember (per-user)",
roles: ["login"],
options: { trustForwardedClientInfo: true }
) {
ok
result { apiKey { id token } }
}
}
The flag cannot be flipped on an existing api_key. To remove it, disable the key and create a new one.
Audit
(since 2.2) Every createApiKey / createGlobalApiKey is recorded as api_key_create in the audit log with the api_key id, identity, and memberships/roles — never the token or its hash. disableApiKey is recorded as api_key_disable.
Listing API keys
Permanent keys can be listed so a management UI can show which keys exist, who they belong to, and when they were last used. Two entry points cover the project-scoped and global cases — both return the enriched ApiKey type and never expose the token.
Project-scoped permanent keys (excludes session tokens and global keys) live on the Project type and require the project.view members permission:
query {
projectBySlug(slug: "my-blog") {
apiKeys {
id
description
type
enabled
createdAt
lastUsedAt
expiresAt
identity {
id
# memberships, handy for cloning a key when re-issuing it
projects {
project { slug }
memberships { role variables { name values } }
}
}
}
}
}
Global permanent keys (those created via createGlobalApiKey — their identity carries global roles and no project membership) are read through the top-level query, gated by the apiKey:list permission (granted only to SUPER_ADMIN by default):
query {
globalApiKeys {
id
description
type
enabled
createdAt
lastUsedAt
expiresAt
identity { id roles }
}
}
Both fields return an empty list rather than throwing when the caller may not list the keys, so a batched query doesn't abort on a single forbidden target.
ApiKey fields
| Field | Notes |
|---|---|
id | The api-key id. Pass to disableApiKey. |
identity | The key's identity — identity.id to edit memberships, identity.projects for its project memberships, identity.roles for a global key's roles. |
description | Human-readable label, stored on the key's identity (identity.description). |
type | ApiKeyType — SESSION, PERMANENT, or ONE_OFF. Listings only return PERMANENT keys. |
enabled | false once the key has been disabled (disableApiKey). |
createdAt | When the key was minted. |
lastUsedAt | Timestamp of the most recent request authenticated with this key. |
expiresAt | Expiration, if any (permanent keys typically have none). |
Session keys vs permanent keys
API keys come in two flavors:
- Permanent — created by
createApiKey/createGlobalApiKey, no expiry, intended for applications and integrations. - Session — minted by
signIn/signInIDP/signInPasswordless/createSessionToken, short-lived, tied to a person. Documented in sessions — there you'll also find how to list and revoke active sessions.
Disable API Key
mutation {
disableApiKey(id: "some-api-key-id") {
ok
}
}
Use the API Key ID to disable the API key. Do not confuse this with the Identity ID.
To invalidate every API key (session and permanent) for a target person at once, use forceSignOutPerson.