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": { "..." }
}
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
| Field | Type | Description |
|---|---|---|
definitions[].key | string | Authorized process definition key |
definitions[].roles | string[] | Roles the user can assume — matched against candidateGroups of tasks |
definitions[].candidate_as_user | boolean | If true, includes tasks where user_id appears in candidateUsers. Default: false |
definitions[].can_start | boolean | Whether the user can start new instances of this definition |
definitions[].max_concurrent | integer | null | Maximum 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.