Skip to content

Authorization

Authorization in Strøm is optional and config-driven. When no acl section is present in server-config.yaml, all authenticated users have full access (backward compatible). Adding the acl section enables fine-grained access control.

Admin users bypass all ACL rules and always have full access. They can manage other users, toggle admin status, and assign groups.

Groups are named sets of users (e.g., devops, engineering, qa). Groups are stored in the database and managed via the UI or API. You reference them in ACL rules without pre-creating them.

ACL rules define what users/groups can do with which workspaces and tasks. Each rule specifies an action: run (full access), view (read-only), or deny (invisible).

acl:
default: deny # What happens when no rule matches: deny | view | run
rules:
- workspace: "production"
tasks: ["deploy/*"]
action: run
groups: [devops]
users: [contractor@ext.com]
- workspace: "*"
tasks: ["*"]
action: view
groups: [engineering]
FieldDescription
defaultDefault action when no rule matches: deny, view, or run. Defaults to deny.
rulesList of ACL rules (each with workspace, tasks, action, groups, users)
workspaceExact workspace name or * (all workspaces). Supports * wildcard.
tasksList of task patterns. Task path is "{folder}/{task_name}" when a folder is set, or just "{task_name}". Supports * wildcard (e.g., ["deploy/*", "rollback"]).
actionrun (full access), view (read-only), or deny (invisible).
groupsList of group names to match (OR’d with users).
usersList of user email addresses to match (OR’d with groups).
  1. If user is admin → always Run (full access)
  2. If no ACL is configured → always Run (backward compatible)
  3. Check all matching rules (workspace + tasks match) → highest permission wins (Run > View > Deny)
    • Order of rules in config doesn’t matter
    • If a rule matches workspace and task patterns, check if user/groups match
  4. If no rules matched → use acl.default (defaults to deny)
PermissionSee in listExecute/cancelView logs
Run
View
Deny

The initial user (from auth.initial_user in config) is automatically promoted to admin on startup.

When OIDC SSO is enabled, the first user to sign in becomes admin if no users exist yet.

Admins can:

  • View and manage all users and groups (Users page)
  • View and manage workers (Workers page)
  • Toggle admin status on other users
  • Create, update, and delete user groups

Via the UI:

  1. Navigate to Users page (admin only)
  2. Click on a user
  3. Toggle the Administrator switch

Via the API:

Terminal window
curl -X PUT https://stroem.example.com/api/users/{id}/admin \
-H "Authorization: Bearer <jwt-token>" \
-H "Content-Type: application/json" \
-d '{"is_admin": true}'

Groups are named sets of users. Create them by assigning them to users — they’re materialized on first use.

  1. Navigate to Users page (admin only)
  2. Click on a user
  3. In the Administration card, find the Groups section
  4. Type a group name and click “Add” (existing groups auto-suggest)
  5. Click the X next to a group to remove it
  6. Changes are saved immediately
Terminal window
# Get a user's groups
curl https://stroem.example.com/api/users/{id}/groups \
-H "Authorization: Bearer <jwt-token>"
# Set a user's groups
curl -X PUT https://stroem.example.com/api/users/{id}/groups \
-H "Authorization: Bearer <jwt-token>" \
-H "Content-Type: application/json" \
-d '{"groups": ["devops", "engineering"]}'
# List all distinct group names
curl https://stroem.example.com/api/groups \
-H "Authorization: Bearer <jwt-token>"

Group names must be 1-64 characters, alphanumeric with underscores and hyphens.

acl:
default: deny
rules:
# DevOps team can run everything everywhere
- workspace: "*"
tasks: ["*"]
action: run
groups: [devops]
# Backend team can run tasks in staging, view production
- workspace: "staging"
tasks: ["*"]
action: run
groups: [backend]
- workspace: "production"
tasks: ["*"]
action: view
groups: [backend]
# QA can run test tasks anywhere
- workspace: "*"
tasks: ["test/*", "qa/*"]
action: run
groups: [qa]
acl:
default: deny
rules:
# Contractors can only run specific tasks
- workspace: "production"
tasks: ["reports/daily-summary", "reports/weekly-digest"]
action: run
users: [contractor@ext.com]
# Everyone else gets view-only
- workspace: "*"
tasks: ["*"]
action: view
groups: [employees]
acl:
default: deny
rules:
# Developers have full access to dev workspace
- workspace: "dev"
tasks: ["*"]
action: run
groups: [developers]
# Staging is open for experimentation
- workspace: "staging"
tasks: ["*"]
action: run
groups: [developers, qa]
# Production is tightly controlled
- workspace: "production"
tasks: ["deploy/*"]
action: run
groups: [devops]
- workspace: "production"
tasks: ["*"]
action: view
groups: [developers, qa]

When you revoke a user’s admin status or change their group assignments, those changes take effect immediately for new requests.

However, existing JWT access tokens (15-minute TTL) remain valid until they expire. If you need to revoke access immediately, the user’s token will still work for up to 15 minutes.

API keys reflect changes immediately — they are validated against the database on each request.

Use the acl section in the server config:

server:
config:
acl:
default: deny
rules:
- workspace: "*"
tasks: ["*"]
action: run
groups: [admin-team]
- workspace: "*"
tasks: ["*"]
action: view
groups: [engineering]

If using Helm secrets, remember that the ACL config is baked into the ConfigMap (it’s not secret). Group assignments are stored in the database and managed via API.

  • Webhooks (/hooks/{name}) use their own secret-based authentication, not user ACL. They are not subject to ACL rules.
  • JWT token TTL: After revoking admin status or changing groups, existing tokens remain valid for up to 15 minutes (the access token TTL). This is by design to avoid excessive database queries on each request.
EndpointMethodDescriptionAuth
/api/usersGETList all usersJWT (admin)
/api/users/{id}GETGet user detailJWT (admin)
/api/users/{id}/adminPUTSet admin flagJWT (admin)
/api/users/{id}/groupsGETGet user’s groupsJWT (admin)
/api/users/{id}/groupsPUTSet user’s groupsJWT (admin)
/api/groupsGETList all group namesJWT (admin)

See Auth API for full endpoint details.