Skip to main content

Managing access

Access in TagShape is: permissions go on groups, people go in groups. There is nothing else.

Setting up a group

POST /groups
{
"name": "Readers",
"description": "Can see the library but not change it",
"permissions": [
"TagGroupList", "TagGroupRead",
"TagList", "TagRead",
"VariableList", "VariableRead"
]
}

Needs GroupCreate, and the ability to grant each permission listed. See granting versus holding.

Two checks run beyond the endpoint permission:

  • Grant check — a permission being added that you cannot grant is rejected, and named in the response.
  • Dependency check — a group carrying AuditRead without AuditList is refused. The permission would do nothing, and a group that silently does nothing is worse than a rejected save.

Adding people

PUT /groups/{id}/members
{ "userIds": ["9c1e7a4d-…", "3f52a18b-…"] }

Needs GroupUpdate and no grant check — adding somebody to a group is not the same act as deciding what the group may do.

Changes take effect at the member's next token refresh, not immediately. With the default one-hour token that is at most an hour.

A worked set of groups

A shape that works for most organizations:

GroupPermissionsFor
ReadersTagGroupList, TagGroupRead, TagList, TagRead, VariableList, VariableReadAnyone who needs to see the library
EditorsReaders + TagGroupCreate/Update/Delete, TagCreate/Update/Delete, VariableCreate/Update/DeletePeople who maintain configuration
Secret readersVariableRead, VariableReadSecretsThe few who need actual secret values
ImportersBatchProcessingImportPipeline accounts that apply a library file
DeploymentVariableRead, VariableReadSecretsAccounts behind deployment API keys
AuditorsAuditList, AuditReadCompliance and investigation
AdministratorsUserListUserDelete, GroupListGroupDelete, PermissionsAllPeople who manage access
PlatformPermissionsAllGlobal, OrganizationListOrganizationDelete, AuditGlobalList, AuditGlobalReadWhoever runs the installation

Two things worth noticing.

Secret readers is separable from Editors. Writing a sensitive value needs only VariableUpdate, so the people who maintain configuration need not be the people who can read the secrets in it.

Administrators holds PermissionsAll, not every permission. PermissionsAll lets them hand out any non-global permission without their being able to use any of them. An administrator can put VariableReadSecrets on a group without becoming a reader of secrets.

Global permissions

Six permissions reach beyond one organization, and only somebody holding PermissionsAllGlobal can hand any of them out:

PermissionsAllGlobal, PermissionsImpersonate, AuditGlobalList, AuditGlobalRead, and the five Organization* permissions.

Keep them to a single platform group with very few members.

Issuing API keys

A key carries the permissions of the account that owns it, so the way to scope a key is to scope its account.

  1. Create an account for the consumer — not a person's account.
  2. Put it in a group holding only what the consumer needs.
  3. Grant that account ProfileCreateApiKey.
  4. Sign in as it and create the key.

For a key that never expires the account also needs ProfileNeverExpiresApiKey. Think twice: a key that never expires is one that cannot be forgotten about safely, which is why it is a separate decision.

See API keys.

Reviewing access

QuestionWhere
What can this person do?GET /users/{id} — their groups and the permissions those carry
Who is in this group?GET /groups/{id}
What keys does this account hold?GET /users/{id}/apikeys — needs UserRead
Who changed a group, and when?Audit log, entryType of Group
What permissions exist?GET /permissions

Removing access

To removeDo
One person's accessTake them out of the group, or delete the account (UserDelete)
A capability from everyone in a groupTake the permission off the group (GroupUpdate)
A machine credentialDELETE /users/{id}/apikeys/{apiKeyId} (UserDelete)

Deleting an account does not retroactively invalidate an already-minted JWT. A token remains valid until it expires — at most an hour by default. Where that matters, shorten Jwt:DurationInMinutes.

Common mistakes

Granting AuditRead alone. It depends on AuditList and does nothing without it. The group save will refuse it.

Granting VariableReadSecrets alone. Same reason — it depends on VariableRead.

Expecting PermissionsAll to let somebody do things. It governs granting, not doing. Somebody with only PermissionsAll cannot read a single variable.

Expecting a permission change to take effect immediately. It reaches the caller at their next token refresh.