Skip to main content

Organizations

An organization is the tenancy boundary. Every record in TagShape belongs to exactly one, and nothing reaches across.

What an organization holds

Held inRecords
Account APIUsers, groups and their permissions, identity providers, branding, account patterns, API keys
Library set APITag groups, tags, library sets, variables, values
Audit APILog entries

How the boundary is enforced

Every query is filtered by the org claim on the caller's JWT. The consequence worth knowing is that an ID belonging to another organization does not produce a 403 — it produces a 404. As far as the query is concerned the record is not there, and saying otherwise would confirm that an ID exists.

The exceptions are the four global organization permissions (OrganizationList, OrganizationRead, OrganizationCreate, OrganizationUpdate, OrganizationDelete), which by their nature reach beyond a single organization. See Permissions model for what global means and who may hand one out.

Identity providers

An organization brings its own. Each provider record holds the client ID, client secret and any tenant identifier needed to run a login, and the login page offers whichever ones the organization has configured. Microsoft Entra ID and Google are supported. See Identity providers.

Credentials can be tested before they are saved, via POST /organizations/identityproviders/check — the check runs server-side rather than from the browser, because Entra's token endpoint allows the CORS preflight and then omits the Access-Control-Allow-Origin header from the response, so a browser never gets the reply.

Account patterns

An organization can say that email addresses matching a pattern may have an account created for them automatically at first login. When someone signs in successfully with a provider but has no account, POST /users/provision checks their address against the organization's patterns; a match creates the account, and no match refuses the login.

A pattern that cannot be compiled is logged and passed over rather than failing the login.

Branding

An organization can supply a logo and custom CSS, both served to the login page by GET /organizations/{id}/signin. The CSS is filtered against an allow-list of rules rather than injected wholesale.

Which organization is being signed in to

The auth UI resolves the organization per request. Where nothing in front of the deployment sets it, the x-tagshape-org header names it — that is how the local Aspire host runs it.

Deleting an organization

DELETE /organizations/{id} needs the global OrganizationDelete. A disabled organization (active: false) stops answering GET /organizations/{id}/signin — an ID naming a disabled organization and an ID naming no organization get the same 404, because in both cases there is nothing there to sign in to.