Skip to main content
Every authenticated request passes three checks in order, and a request that reaches a secret has cleared all three.
1

Workspace membership

The caller must be a member of the workspace named in the path (or, on routes without one, in the X-Workspace-Id header or the credential’s own scope). A non-member gets 403, and a workspace that does not exist gets 404.
2

Team membership

The caller must be a member of the team that owns the project. This is the gate that actually keeps one team’s secrets away from another’s — being in the workspace is not enough.
3

Project ownership

The project must genuinely belong to that team and workspace. A project id borrowed from another scope reads as 404, not as an authorisation error.

Roles

Workspace membership carries one of four roles, ordered:
The boundaries Sink enforces today are workspace membership, team membership, and owner-only operations. The Viewer / Member distinction is stored on the membership but does not yet restrict writes at the secret layer — anyone in the team can read and write that team’s secrets. Use team membership, not role, to scope who can change production values for now.

Owner-only operations

  • Renaming or deleting a workspace
  • Inviting someone to a workspace
  • DELETE on an environment’s entire secret set

Admin-or-owner operations

  • Creating a team
  • Listing every team in the workspace (others see only the teams they are in)

Inviting people

An owner sends an invite to an email address, optionally naming a team and a role:
The invitee gets an email with a link. They can check it without committing to anything (POST /invite/validate?token=…), accept it (POST /invite/accept, which creates the account and signs them in if they are new), or decline it (POST /invite/reject?token=…). Invites carry a status of pending, accepted, rejected or expired, and GET /invite/{workspace_id} lists them. Sending an invite counts against the workspace’s seat limit, so a full workspace is refused with 402 before any mail goes out.
An invite link is a bearer token. Anyone who reads the email can accept it. The three token routes share a rate-limit budget so they cannot be worked through in rotation, but the real protection is that the link goes to an address you chose.

Credentials and scope

A session JWT carries a workspace claim from the login that minted it. An API key carries no workspace of its own — it falls back to the holder’s current workspace, and a path parameter overrides that. In both cases the workspace in the URL wins, so a key cannot reach past its holder’s memberships by omitting one. An API key inherits the permissions of the user who created it. There is no way to mint a key that is weaker than its owner, so a key handed to a pipeline should belong to an account whose access you are comfortable with the pipeline having.

Leaving and deleting

Deleting an account removes the workspaces it owns — along with their teams, projects, environments and secrets — and leaves the workspaces where it was only a member. The response says how many of each. It is irreversible and asks for the password to confirm.