uslimato
|

API Key Scopes

TL;DR

  • Global keys belong to the tenant. They carry exactly the API scopes you chose at mint time. Use them for service accounts.
  • User-bound keys belong to a specific user. Their effective scope is the intersection of the key's stored scopes and the owner's currently-granted permissions, evaluated live on every request. Use them when the automation should track a real person's authority.
  • An owner deactivation, a permission revoke, or a group-membership change propagates to user-bound keys within 60 seconds.

Why Two Scope Types?

The original design treated every key as tenant-wide. That works fine for monitoring agents and CI jobs, but it creates two problems for keys that represent a person's automation:

  1. Ghost permissions. A user leaves the company, the admin disables the user account — but their personal API key keeps working until someone notices and revokes it manually.
  2. Stale snapshots. The key was minted while the user had assets:write. Months later the user was demoted to read-only — but the key still grants write access.

User-bound keys fix both issues by binding the key to the owner's user account and re-evaluating permissions live.

Permission Intersection (User-Bound Keys)

A user-bound key carries a stored scope set chosen at mint time (e.g. ["assets:read", "assets:write"]). On every request, the auth middleware:

  1. Checks whether the owner's user account is active. If not → access denied.
  2. Resolves the owner's current permissions (updated within 60 seconds).
  3. Maps named permissions to API scopes:
    • admin → all eight API scopes (wildcard)
    • assets:writeassets:read + assets:write
    • assets:useassets:read
    • users:manageusers:read + users:write
    • processes:manageprocesses:read + processes:write
    • processes:useprocesses:read
    • tickets:manage / tickets:admintickets:read + tickets:write
    • tickets:create / tickets:closetickets:read
  4. The effective scope set is the intersection of the key's stored scopes and the owner's live API scopes.

A key can never grant more than the owner currently holds. A request whose required scope is missing from the intersection returns 403 INSUFFICIENT_SCOPE.

Update Behaviour

Owner permissions are cached for up to 60 seconds. On group-membership or group-permission changes the cache is refreshed immediately, so a revoked permission takes effect on the next request.

Ownership Rules at Mint Time

Callerscope_typeuser_idResult
any(missing)400 SCOPE_REQUIRED
adminglobalnull201
adminglobalnon-null400 VALIDATION_ERROR
non-adminglobal403 GLOBAL_KEY_ADMIN_ONLY
adminusertenant member201
adminusercross-tenant400 INVALID_USER
non-adminuserself201
non-adminusersomeone else403 FORBIDDEN

scope_type has no default. Callers must always pick explicitly.

Owner Lifecycle Effects

EventEffect on user-bound keys
Owner removed from permission groupEffective scope shrinks within 60s
Owner deactivatedNext request is denied
Owner deletedKey is automatically removed
Admin revokes the key explicitlyKey is deactivated

When to Use Which

Pick Global when:

  • The key represents a service, not a person (CI, backups, monitoring).
  • You need a key that survives any individual employee leaving.
  • The integration needs broad scope that is intentionally not tied to anyone's role.

Pick User-Bound when:

  • The key represents a person's automation (personal CLI, browser extension, IFTTT).
  • You want the key to follow the user's role changes automatically.
  • Off-boarding should disable the key as a side effect of disabling the user.

When in doubt: prefer user-bound. The "ghost permission" failure mode is far more common than the cases where global is genuinely required.