Skip to main content

Credentials

Stateway provides an encrypted credential store so you can reference secrets — API tokens, access keys, passwords — in process definitions without embedding them in plaintext.

Why not put secrets directly in BPMN

Embedding secrets directly in task headers is dangerous:

<!-- ❌ Never do this -->
<stateway:header key="headers" value='{"Authorization": "Bearer sk_live_abc123..."}' />

The value is stored in plaintext in the source column of process_definitions, appears in XML exports (GET /definitions/:key/xml), and in any database dump. A definition leak becomes a credential leak.

Creating a credential

Request:

curl -X POST https://api.stateway.io/v1/credentials \
-H "X-API-Key: sw_live_..." \
-H "Content-Type: application/json" \
-d '{
"name": "payment_api_token",
"value": "sk_live_abc123...",
"description": "Payment gateway API token"
}'

Response:

{
"data": {
"id": "cred_01j...",
"name": "payment_api_token",
"description": "Payment gateway API token",
"created_at": "2026-05-01T12:00:00.000Z"
}
}

The value is encrypted with AES-256-GCM before being persisted. The value is never returned by the API after creation. To replace it, use PATCH.

Rules for name:

  • Lowercase letters, digits, and underscores only
  • Must start with a lowercase letter
  • Maximum 64 characters
  • Examples: payment_api_token, fraud_service_key, internal_auth

Listing credentials

Returns metadata only — values are never included.

Request:

curl https://api.stateway.io/v1/credentials \
-H "X-API-Key: sw_live_..."

Response:

{
"data": [
{
"id": "cred_01j...",
"name": "payment_api_token",
"description": "Payment gateway API token",
"created_at": "2026-05-01T12:00:00.000Z",
"updated_at": "2026-05-01T12:00:00.000Z"
}
]
}

Requires the credentials:read or admin scope.

Getting a credential by name

Request:

curl https://api.stateway.io/v1/credentials/payment_api_token \
-H "X-API-Key: sw_live_..."

Response:

{
"data": {
"id": "cred_01j...",
"name": "payment_api_token",
"description": "Payment gateway API token",
"created_at": "2026-05-01T12:00:00.000Z",
"updated_at": "2026-05-01T12:00:00.000Z"
}
}

Requires the credentials:read or admin scope.

Using credentials in service tasks

Reference a credential with the {{credentials.name}} syntax anywhere in taskHeaders:

<bpmn:serviceTask id="callPaymentApi" name="Charge Payment">
<bpmn:extensionElements>
<stateway:taskDefinition type="http" />
<stateway:taskHeaders>
<stateway:header key="url" value="https://api.payment.com/charge" />
<stateway:header key="method" value="POST" />
<stateway:header key="headers" value='{"Authorization": "Bearer {{credentials.payment_api_token}}"}' />
</stateway:taskHeaders>
</bpmn:extensionElements>
</bpmn:serviceTask>

The engine resolves the reference at execution time: the decrypted value exists only in memory during token execution and is never written to logs, the audit log, or webhook payloads.

Rotating a credential

To replace the value without touching any process definition that references it:

Request:

curl -X PATCH https://api.stateway.io/v1/credentials/payment_api_token \
-H "X-API-Key: sw_live_..." \
-H "Content-Type: application/json" \
-d '{ "value": "sk_live_xyz456..." }'

Response:

{
"data": {
"id": "cred_01j...",
"name": "payment_api_token",
"description": "Payment gateway API token",
"created_at": "2026-05-01T12:00:00.000Z",
"updated_at": "2026-05-13T09:00:00.000Z"
}
}

All instances started after the rotation will use the new value automatically. Instances already in progress that have not yet reached the service task will also pick up the new value.

You can also update the description without changing the value:

Request:

curl -X PATCH https://api.stateway.io/v1/credentials/payment_api_token \
-H "X-API-Key: sw_live_..." \
-H "Content-Type: application/json" \
-d '{ "description": "Payment gateway token (renewed May 2026)" }'

Response:

{
"data": {
"id": "cred_01j...",
"name": "payment_api_token",
"description": "Payment gateway token (renewed May 2026)",
"created_at": "2026-05-01T12:00:00.000Z",
"updated_at": "2026-05-13T09:05:00.000Z"
}
}

Deleting a credential

Request:

curl -X DELETE https://api.stateway.io/v1/credentials/payment_api_token \
-H "X-API-Key: sw_live_..."

Returns 204 No Content. The deletion is soft — the credential is marked as deleted and no longer resolvable by the engine. Any process that references {{credentials.payment_api_token}} after deletion will fail at the service task with a credential resolution error.

Required scopes

OperationRequired scope
GET /v1/credentialscredentials:read or admin
GET /v1/credentials/:namecredentials:read or admin
POST /v1/credentialscredentials:write or admin
PATCH /v1/credentials/:namecredentials:write or admin
DELETE /v1/credentials/:namecredentials:write or admin

Security limitations

The current security model does not protect against:

  • Direct access to the application process (anyone who can exec into the container can decrypt)
  • Compromise of the Kubernetes cluster (K8s secrets would be accessible)
Values may be unrecoverable if the encryption key is lost

Stateway encrypts credentials with a platform-managed key. If that key is lost, rotated unexpectedly, or compromised, stored values may be permanently and irrecoverably lost.

Always keep independent, secure copies of your original credentials. The Credential Endpoint is a runtime reference mechanism — not a primary secret store.