Indexhog - Search indexing and monitoring

Scopes & Permissions

The permission system that governs sessions, Personal Access Tokens, and OAuth clients — and how to pick the right scopes for your integration

5 min read

Every authenticated request carries a permission set. Sessions get the full set of user-facing permissions; Personal Access Tokens (PATs) and OAuth client tokens get only the scopes you grant at creation time. A request missing a required scope fails with INSUFFICIENT_PERMISSIONS.

Quick Reference

All user-facing scopes, grouped by the resource they govern.

CategoryScopes
User profileuser:read, user:write
Projectsprojects:read, projects:write
Subscriptionsubscription:read, subscription:write
API keysapi-keys:read, api-keys:write, api-keys:delete
Organizationorganization:read, organization:manage-members, organization:manage-billing, organization:manage-security

These are the scopes you can include in a PAT's metadata.scopes array or request from an OAuth client. Organization scopes must be requested explicitly and are then capped by the caller's current role in that organization.

How scopes are assigned

Session users

When a user signs in, their session carries the full set of user-facing permissions listed above. You cannot narrow a session's scopes — narrowing happens at the UI layer.

Personal Access Tokens

When you create a PAT via POST /api/auth/api-key/create, you pass an explicit metadata.scopes array. The token can never exceed the user's own permissions, and any scope you leave out is blocked even if the owning user has it. This is the mechanism you use to lock down a CI bot.

POST /api/auth/api-key/create
{
"name": "Build status poller",
"metadata": { "scopes": ["projects:read", "subscription:read"] },
"expiresIn": 2592000
}

OAuth clients

OAuth clients request scopes during the Authorization Code flow. The end user approves them at consent time, and the issued access token carries exactly those scopes.

Scope Reference

user:read

Read the signed-in user's account, login history, email preferences, and data export.

Endpoints:

  • GET /api/user/me
  • GET /api/user/me/login-history
  • GET /api/user/me/email-preferences
  • GET /api/user/me/export

user:write

Update email preferences and account state (deletion, recovery). Product identity is email-only — there is no profile/handle/avatar mutation.

Endpoints:

  • PUT /api/user/me/email-preferences
  • POST /api/user/me/recover
  • DELETE /api/user/me

projects:read

List and read projects and Indexhog operational resources inside an organization (tenant route — the organization id is part of the URL path).

Endpoints (representative):

  • GET /api/user/organizations/{organizationId}/projects
  • GET /api/user/organizations/{organizationId}/projects/:id
  • GET /api/user/organizations/{organizationId}/projects/:id/verification
  • GET /api/user/organizations/{organizationId}/projects/:id/urls
  • GET /api/user/organizations/{organizationId}/projects/:id/issues
  • GET /api/user/organizations/{organizationId}/projects/:id/stats

projects:write

Create and update projects, manage verification, inventory, imports, issue status, and engine connections.

Endpoints (representative):

  • POST /api/user/organizations/{organizationId}/projects
  • PUT /api/user/organizations/{organizationId}/projects/:id
  • DELETE /api/user/organizations/{organizationId}/projects/:id
  • PATCH /api/user/organizations/{organizationId}/projects/:id/status
  • POST /api/user/organizations/{organizationId}/projects/:id/verification/*
  • POST /api/user/organizations/{organizationId}/projects/:id/urls
  • POST /api/user/organizations/{organizationId}/projects/:id/imports
  • PATCH /api/user/organizations/{organizationId}/projects/:id/issues/:issueId

subscription:read

Read the current organization's subscription state, plan, and usage counters.

Endpoints:

  • GET /api/user/organizations/{organizationId}/payments/subscription
  • GET /api/user/organizations/{organizationId}/payments/subscription/usage

subscription:write

Start checkouts, change subscription details (including seat count), buy one-time add-ons, and open the customer billing portal. Most write endpoints additionally require the requested organization:manage-billing scope and an owner role.

Endpoints:

  • POST /api/user/organizations/{organizationId}/payments/checkout
  • POST /api/user/organizations/{organizationId}/payments/verify
  • PATCH /api/user/organizations/{organizationId}/payments/subscription
  • GET /api/user/organizations/{organizationId}/payments/portal

organization:read

Read organization details, members, security requirements, verified domains, and subscription usage. A delegated credential must request this scope; membership alone does not add it.

organization:manage-members

Update organization settings and membership: invitations, roles, removals, ownership transfer, and member-facing MFA policy. The effective permission is also capped by the caller's organization role.

organization:manage-billing

Manage billing settings, subscription commands, purchase intents, and verified domains. This scope is owner-only after the role ceiling is applied.

organization:manage-security

Change organization security configuration such as SSO. This scope is owner-only after the role ceiling is applied.

api-keys:read

List OAuth applications and PATs belonging to the signed-in user.

Endpoints:

  • GET /api/user/oauth-clients
  • GET /api/user/oauth-clients/:clientId
  • GET /api/auth/api-key/list
  • GET /api/auth/api-key/get

api-keys:write

Create and update OAuth applications and PATs.

Endpoints:

  • POST /api/auth/oauth2/register
  • PUT /api/user/oauth-clients/:clientId
  • POST /api/user/oauth-clients/:clientId/regenerate-secret
  • POST /api/user/oauth-clients/:clientId/toggle
  • POST /api/auth/api-key/create
  • POST /api/auth/api-key/update

api-keys:delete

Delete OAuth applications and revoke PATs.

Endpoints:

  • DELETE /api/user/oauth-clients/:clientId
  • POST /api/auth/api-key/delete

Common scope sets

Read-only dashboard

For a UI that displays projects and subscription status but never writes.

["user:read", "projects:read", "subscription:read", "organization:read"]

CI bot that manages projects

For a deploy bot that creates and updates project records and inventory.

["projects:read", "projects:write", "organization:read"]

Billing automation

For a service that manages seat counts, credit top-ups, and renewals on behalf of an organization.

["subscription:read", "subscription:write", "organization:read", "organization:manage-billing"]

Token manager (lifecycle only)

For tooling that provisions and rotates PATs on behalf of a user.

["api-keys:read", "api-keys:write", "api-keys:delete"]

Organization pinning

PATs may be pinned to a single organization by passing metadata.organizationId at creation time. A pinned token rejects any request whose URL :organizationId does not match the pin — even if the owner is a member of other organizations.

POST /api/auth/api-key/create
{
"name": "Acme prod bot",
"metadata": {
  "scopes": ["projects:read", "projects:write", "organization:read"],
  "organizationId": "01HZ3K5R4X9Y2V6QF8TJ7W0CDN"
}
}

Use this for any token that should only ever touch one tenant. It is a far smaller blast radius than relying on the caller to send the right URL.

Scope enforcement

When a request lacks a required scope, the API returns:

{
"success": false,
"status": 403,
"code": "INSUFFICIENT_PERMISSIONS",
"message": "Insufficient permissions. Required: projects:write",
"meta": {}
}

This is a hard failure — retrying will not fix it. Either issue a new token with the missing scope or sign in as a user who has it.

Best Practices

  • Least privilege always: The correct number of scopes on a token is the smallest set that makes the automation work. Err on fewer and add later.
  • Pair reads and writes deliberately: A bot that only needs projects:read should never get projects:write, even "just in case."
  • Pin production tokens to an organization: Accidents at the URL layer become FORBIDDEN responses instead of cross-tenant writes.
  • Rotate on schedule: Pass expiresIn (in seconds) so tokens die on their own. Build rotation into CI secrets management.
  • Never log the key value: The tkn_* prefix makes them easy to grep for — do not hand leakers the job.
  • One automation, one token: Revocation becomes surgical instead of catastrophic.

Next Steps

  1. Set up SSO for your team: Follow Enterprise SSO to require corporate identity for domain users.
  2. Issue your first token: Walk through Quick Start to create one with the scopes you just picked.
  3. Plan for rate limits: See Rate Limits before running anything in a loop.
  4. Browse endpoints: Open the API Keys reference or the Projects reference to start integrating.