Roles
Bundling permissions onto a membership, addressed by slug.
View as MarkdownA role bundles permissions. The backend authorizes on the resolved permissions and never reads the role itself, which is why a custom role you invent is enforced correctly without us knowing it exists.
List
curl -fsS "https://api.saved.sh/v1/workspaces/$WID/roles" \
-H "Authorization: Bearer $TOKEN"{
"data": [
{ "slug": "admin", "name": "Admin", "description": "Full access", "permissions": ["..."] },
{ "slug": "member", "name": "Member", "description": "", "permissions": [] },
{ "slug": "org_auditor", "name": "Auditor", "description": "Read-only",
"permissions": ["workspaces:read", "backups:read", "artifacts:read", "audit:read"] }
],
"next_cursor": null
}Permission: roles:read.
| Role | Carries |
|---|---|
admin | Every permission in the catalog |
member | Nothing, by default |
| Custom | Whatever you grant |
A bare member has no access at all. That is deliberate, so nobody is granted anything by
simply existing, but it means an invitation without a role always needs a follow-up.
Custom roles are auto-prefixed (org_) by the identity provider. Use the slug exactly as
returned.
Create
curl -fsS -X POST "https://api.saved.sh/v1/workspaces/$WID/roles" \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{
"name": "Auditor",
"description": "Read-only, including the audit trail",
"permissions": ["workspaces:read", "backups:read", "artifacts:read", "audit:read"]
}'Permission: roles:write. Slugs are derived from the name.
Validate against the live catalog rather than a hard-coded list:
curl -fsS https://api.saved.sh/v1/permissions -H "Authorization: Bearer $TOKEN"{ "data": ["workspaces:read", "workspaces:write", "members:read", "..."] }Update
curl -fsS -X PATCH "https://api.saved.sh/v1/workspaces/$WID/roles/$SLUG" \
-H "Authorization: Bearer $TOKEN" \
-H 'Content-Type: application/json' \
-d '{"permissions": ["backups:read", "artifacts:read"]}'permissions replaces the set rather than adding to it. Send the full list you want, or
you will silently remove the ones you left out.
Permission changes take effect when the affected members' tokens are next minted, which is on their next sign-in or token refresh rather than instantly.
Delete
curl -fsS -X DELETE "https://api.saved.sh/v1/workspaces/$WID/roles/$SLUG" \
-H "Authorization: Bearer $TOKEN"Permission: roles:write. Returns 204.
Deleting a role that memberships still hold leaves those people without its permissions. Move them to another role first.
admin and member are seeded and cannot be deleted.
Designing roles
The distinction that matters most is between knowing about a backup and reading its contents.
| Role | Permissions | For |
|---|---|---|
| Auditor | workspaces:read, backups:read, artifacts:read, audit:read | Compliance review with no access to data |
| Operator | The above plus backups:write, workers:read | Runs the backups, cannot exfiltrate |
| Restorer | backups:read, artifacts:read, artifacts:download | Can actually recover, and nothing else |
artifacts:read returns sizes, checksums and key IDs. artifacts:download returns the data.
Most people need only the first.
Multiple roles
A membership may hold several roles, and the effective permission set is their union. The backend sees one flat set and does not know how it was assembled.