Skip to content
Hexel StudioDocs

Session policies

Attach policies to one session to narrow what it can do, and see where they are applied today.

On this page

What a session policy is

A session policy is a policy document attached to one session in your organization. It can only narrow: while a session has session policies, an action is allowed in that session only if at least one of its session policies allows the action and none denies it, on top of everything else that is required. A session policy never grants anything.

A session is identified by the sid claim of an access token:

TokenSession ID
A person's access tokenCreated when they sign in to Hexel Studio, and kept when the access token is refreshed. A new sign-in starts a new session.
A service user's access token (API key or OAuth client)Starts with svc_. It is derived from the credential and changes every 15 minutes.
A role sessionStarts with rs_. Session policies never apply to role sessions.

See Tokens for the claims of an access token.

Where session policies are applied

DecisionSession policies applied?
Your normal API callsNo
POST /v1/authz/evaluate, /simulate and /explain with session_idYes
Role sessionsNo

When they apply, the evaluator reads every session policy of the session in your organization:

  • If the session has none, nothing changes.
  • If any session policy has a Deny statement matching the action, the answer is denied with reason session_policy_denied.
  • If no session policy has an Allow statement matching the action, the answer is denied with reason session_policy_denied.
  • A session policy whose document cannot be read allows nothing.

Session policies are checked before the policies that grant access, so they also limit ABAC rules. Only the Action of each statement is matched: Resource and Condition are ignored.

Attach a session policy

POST /v1/session-policies/{session_id}/policies needs iam:relation:write.

FieldTypeDescription
namestringName of the session policy.
documentstringRequired. A policy document, encoded as a JSON string. It needs at least one statement, and every statement needs Effect (Allow or Deny), a non-empty Action and a Resource.
Bash
curl -X POST https://api.hexelstudio.com/v1/session-policies/<session-id>/policies \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "read-only",
    "document": "{\"Version\": \"2026-02-17\", \"Statement\": [{\"Effect\": \"Allow\", \"Action\": [\"workspace:workspace:read\"], \"Resource\": \"*\"}]}"
  }'

The response is 201 Created:

JSON
{
  "id": "sp_...",
  "session_id": "<session-id>",
  "organization_id": "<org-id>",
  "name": "read-only",
  "document": "{\"Version\": \"2026-02-17\", \"Statement\": [{\"Effect\": \"Allow\", \"Action\": [\"workspace:workspace:read\"], \"Resource\": \"*\"}]}",
  "created_at": "2026-10-20T09:00:00Z"
}

An invalid document answers 400 with the problems found:

JSON
{"error": "session policy document is not valid: statement[0]: missing 'Resource'"}

Hexel Studio does not check that the session exists or belongs to someone in your organization. The session policy is stored in your organization and applies only to decisions made in your organization.

List and delete

CallPermissionResponse
GET /v1/session-policies/{session_id}/policiesiam:relation:readArray of the session's session policies in your organization
DELETE /v1/session-policies/{session_id}/policies/{policy_id}iam:relation:write204, or 404

See the effect in the full evaluator

Pass the session ID to POST /v1/authz/evaluate to see what the full evaluator decides in that session. It needs iam:authz:simulate. See Test access for the rest of this API.

Bash
curl -X POST https://api.hexelstudio.com/v1/authz/evaluate \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "subject_id": "<user-id>",
    "organization_id": "'"$ORG_ID"'",
    "session_id": "<session-id>",
    "action": "workspace:workspace:delete"
  }'
JSON
{
  "allowed": false,
  "reason": "session_policy_denied",
  "cacheable": true,
  "principal": "<user-id>",
  "action": "workspace:workspace:delete",
  "resource_type": "",
  "workspace_id": "",
  "environment_id": "",
  "evaluation_ms": 4
}

The same member calling DELETE /v1/workspaces/... for real is not stopped by the session policy.