Build

Organizations, teams and folder access

Put a studio's people, teams and spaces together, give teams roles in spaces, limit who may change a folder, sign in through your identity provider and export the audit trail.

An organization holds a company's people and its teams. A space can belong to one organization, and then its teams can have roles in it: someone who joins the editorial team gets the editorial team's access to every project at once, and loses it when they leave. Spaces outside organizations work exactly as before.

Organization roleMay
ownerEverything an admin may, plus appoint owners and set up single sign-on. The last owner can't leave.
adminAdd and remove people, make teams, bring spaces they manage into the organization, export the audit trail.
memberSee the organization's people, teams and the spaces they are in.

People and teams

sidespace org create "Harbor Pictures"
sidespace org members "Harbor Pictures" --add [email protected] --role admin
sidespace team create "Harbor Pictures" Editorial
sidespace team add "Harbor Pictures" Editorial [email protected] [email protected]
sidespace org attach "Film A" "Harbor Pictures"     # you manage Film A and are an admin there
sidespace team grant "Film A" Editorial editor

Adding someone to a team adds them to the organization as a member if they weren't. Creating an organization takes a person (tokens need the admin scope); giving a team a role in a space takes a space manager (tokens need members:manage).

A member's role in a space

A person's role in a space is the best of their own grant and the roles of their teams there. GET /v1/spaces/{sid}/members shows all three:

JSON
{ "user": { "email": "[email protected]" }, "role": "editor", "direct_role": "viewer",
  "teams": [{ "id": "team_…", "name": "Editorial", "role": "editor" }] }

direct_role is null for someone who is in the space only through teams. Joining or leaving a team changes their role at once. Removing someone from a space while a team still gives them access is refused with 409, naming the team, because "removed" has to mean gone: take them out of the team, or take the team's role away.

Folder access

A folder can carry rules that limit, or widen, what people may change inside it. They never limit what people see.

  • default_role: the most anyone without a grant may do inside (viewer, commenter or editor; null keeps each person's space role).
  • grants: roles for members of the space (by email) or teams of its organization (by name), which may be above their space role. A viewer can be allowed to upload into one delivery folder.
  • The nearest folder with rules decides. Rules don't add up across levels, so a folder's rules are read in one place.
  • Space managers are never limited, so nobody can lock the space's owner out.
# The edit room may read /final, only Delivery may change it
sidespace access "Film A" /final --default viewer --grant team:Delivery=editor
sidespace access "Film A" /final          # your role there, and which folder decides it
sidespace access "Film A" --list          # every folder with rules
sidespace access "Film A" /final --clear

Every write checks the role at its node: creating (at the parent folder), saving a version, renaming and moving (at the node and at the new parent), deleting, restoring, sidecars, renditions, comments (commenter), share links and runs. A refused write is a 403 whose message names the role the folder needs. GET /v1/spaces/{sid}/nodes/{nid}/access returns your role there, your space_role and the rules that decide it (governed_by), so an app can say so before anyone tries; the web app shows "You are viewer here" on such folders and hides what you can't do.

Single sign-on

An organization can sign its people in through its identity provider with OpenID Connect: Okta, Microsoft Entra ID, Google Workspace, Keycloak, Authing and any other provider that publishes /.well-known/openid-configuration. Owners set it up; admins can read it.

  1. Register the redirect URI with the provider. GET /v1/orgs/{oid}/sso names it, and so does its 404 before single sign-on is set up.
  2. Prove each email domain is yours with a DNS TXT record _sidespace.<domain> whose value is the domain_proof from the same call (sidespace-verify=…). Without it anyone could claim gmail.com.
  3. Connect the provider for those domains:
sidespace org sso "Harbor Pictures" --issuer https://harbor.okta.com --client-id 0oa… \
  --client-secret - --domain harbor.example --required < secret.txt
sidespace org sso "Harbor Pictures"          # show it (never the secret)
sidespace org sso "Harbor Pictures" --off

A domain without its TXT record is refused with 422 code domain_unproven. The client secret is sealed with the server's keys and never returned; leave it out of a later PUT to keep it. With required, email codes stop working for those domains. People who sign in through single sign-on join the organization as members.

Signing in from an app

Apps don't handle the provider's tokens. Start a sign-in with the person's address, open the returned url in a browser, and poll with the handle until it answers:

Shell
curl -X POST https://side.example.com/v1/auth/sso/start -H "Content-Type: application/json" \
  -d '{"email": "[email protected]", "device_name": "Ben’s laptop"}'
# → {"url": "https://harbor.okta.com/…", "handle": "sso_…", "expires_at": "…"}
curl -X POST https://side.example.com/v1/auth/sso/poll -H "Content-Type: application/json" -d '{"handle": "sso_…"}'
# 202 while waiting, 200 with the same tokens as an email sign-in, 410 once expired or collected

start answers 404 when no organization signs that domain in. When POST /v1/auth/email/start (or verify) answers 403 with code sso_required, switch to this flow. sidespace login EMAIL --sso and the web app's sign-in page do exactly that.

Audit export

Admins can export what happened in the organization, oldest first. Tokens need the admin scope.

sidespace org audit "Harbor Pictures" --since 2026-10-01 --format csv -o audit.csv

Each record has at, source, kind, actor_id, actor_email, and where they apply actor_kind (person, agent or plugin), via (the token or AI action), space_id, space_name, target, path and detail. There are two sources:

  • org: changes to the organization (people, teams, space roles, folder rules, single sign-on settings) and every single sign-on.
  • space: every file change in the organization's spaces, from their journals, with the file name as it was. A space brought into the organization brings its history.

since and until take RFC 3339 times or dates; the default is the last 30 days. One export returns at most 200 000 records; for more, ask again from the last record's time. In the web app, admins download it from the organization's Audit export tab.