Skip to main content

Sessions API — Authentication and Scope

Session Model

A frontend session is an ephemeral access token you issue for an end user. It carries three pieces of information: the user's identity (user_id), the access scope (which processes, which roles, which operations), and the TTL.

The user_id is the identifier of the user in your system — it can be a UUID, an email address, or any unique string. Stateway does not validate or interpret this value; it is used only to associate instances to the user and for the audit log.

Creating a Session

Call POST /v1/sessions from your backend using your API Key:

curl -X POST https://api.stateway.io/v1/sessions \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{
"user_id": "user_42",
"user_display": "Jane Smith",
"ttl": 3600,
"scope": {
"definitions": [
{
"key": "expense-approval",
"roles": ["requester"],
"candidate_as_user": false,
"can_start": true,
"max_concurrent": 3
}
],
"variable_visibility": "declared"
}
}'

Response:

{
"session_id": "sess_01j...",
"session_token": "sws_live_Xk9mP2...",
"user_id": "user_42",
"expires_at": "2026-05-02T15:00:00Z",
"scope": { "..." }
}
Token shown once

The session_token is returned only once. Store it nowhere on the backend — forward it immediately to the frontend. Stateway stores only a SHA-256 hash.

Scope Fields

FieldTypeDescription
definitions[].keystringAuthorized process definition key
definitions[].rolesstring[]Roles the user can assume — matched against candidateGroups of tasks
definitions[].candidate_as_userbooleanIf true, includes tasks where user_id appears in candidateUsers. Default: false
definitions[].can_startbooleanWhether the user can start new instances of this definition
definitions[].max_concurrentinteger | nullMaximum simultaneous open instances for this user. null = unlimited
variable_visibility"declared" | "all"Variable visibility policy. Default: "declared"

Roles and Candidate Groups

roles defines which BPMN groups the user can assume. A user receives tasks whose assignee matches their user_id, or whose candidateGroups contains a value listed in roles.

{
"key": "loan-application",
"roles": ["analyst", "supervisor"],
"candidate_as_user": false,
"can_start": false,
"max_concurrent": null
}

In this example, the user receives tasks assigned to them directly or assigned to the groups analyst or supervisor. They cannot start new instances. They may have any number of simultaneous open instances.

candidate_as_user

The candidate_as_user field instructs Stateway to include tasks where the user's user_id appears in candidateUsers. Enable this when the process may name users individually as candidates — for example, when an external system designates which specific analyst should review a case:

{
"key": "case-review",
"roles": [],
"candidate_as_user": true,
"can_start": false,
"max_concurrent": null
}

This field is false by default. Enable it only when the process actually uses individual candidateUsers for that definition.

Other Session Endpoints

GET /v1/sessions/:id Inspect active session
DELETE /v1/sessions/:id Revoke session (user logout)
POST /v1/sessions/:id/refresh Extend TTL of active session

Refreshing a session extends the TTL without invalidating the token. Useful for long-lived sessions with silent renewal:

curl -X POST https://api.stateway.io/v1/sessions/sess_01j.../refresh \
-H "X-API-Key: sw_live_your_key" \
-H "Content-Type: application/json" \
-d '{ "ttl": 3600 }'

The SDK emits a session.expiring event 5 minutes before expiry — a good moment to trigger a refresh:

sw.on('session.expiring', async ({ expiresIn }) => {
if (expiresIn < 300) {
const newExpiry = await myBackend.refreshStatewaySession();
// token remains the same; only expires_at changes
}
});

Session Continuity

If a user logs out and back in — creating a new session with the same user_id — running instances are automatically transferred to the new session. The previous session is invalidated. No instances are lost.

The session.superseded event is emitted to any active WebSocket connection using the old session token, and the connection is closed by the proxy.