Auth And Scopes
Use this page to choose the correct auth surface and least-privilege management scopes before you start calling the API.
Who This Is For
- developers creating or rotating management API keys
- AI agents selecting scopes for an automation task
- operators debugging
401and403 TOKEN_SCOPE_DENIEDresponses
When To Use This
Read this before creating keys, wiring SDK clients, or documenting example requests.
This page is intentionally scope-first because auth mistakes are one of the most common reasons integrations fail early.
How It Works
Three auth surfaces
| Surface | Header | Used for | Success shape |
|---|---|---|---|
| Management | Authorization: Bearer <token> | catalog setup, licenses, devices, events, webhooks, reporting | {data, meta} |
| Runtime | Authorization: License <license-key> | activation, validation, check, consume, deactivate, offline issuance, floating leases | {data, signature, meta} |
| System | none | public keys, health, readiness, metrics | endpoint-specific |
Do not reuse a management bearer token for runtime requests. Do not put a license key on management routes.
Scope model
Management operations expose least-privilege requirements via the operation-level x-required-scopes field in api/openapi.yaml.
Current management scopes are:
| Scope | Use it for |
|---|---|
admin | bootstrap, API-key management, customer records, any management route |
product:read | read products, policies, features, versions, orders, subscriptions |
product:write | create and update catalog resources |
license:read | read licenses, devices, license features, license custom fields |
license:write | issue, renew, suspend, reinstate, revoke, transfer, assign features, reset usage |
device:write | device reset and blacklist |
event:read | raw audit event feed |
ops:read | ops summary, runtime-error groups, webhook health |
report:read | activity feed and reporting read endpoints |
report:export | export creation, export metadata, export download |
webhook:write | webhook endpoint management |
Important rules:
adminsatisfies every management route even when a narrower scope is listed.- customer routes are currently
admin-only. - webhook read routes currently still require
webhook:write. - reporting read and export scopes are separate on purpose.
Common scope bundles
Use these as a starting point, then confirm against the exact operation:
- catalog setup:
product:write - catalog readback:
product:read - license issuance and lifecycle:
license:write - license and device inspection:
license:read - device reset and blacklist:
device:write - raw audit polling:
event:read - operator rollups:
ops:read - reporting reads:
report:read - frozen exports:
report:export
Example
Create a scoped management key with admin, then use narrower keys for routine automation:
curl -X POST https://api.licensekit.dev/api/v1/api-keys \
-H "Authorization: Bearer $BOOTSTRAP_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "license-writer",
"scopes": ["license:write"]
}'If you are using the TypeScript SDK, scope metadata can be queried by operationId:
import { getRequiredScopes, hasRequiredScopes } from "@licensekit/sdk";
const required = getRequiredScopes("createLicense");
const allowed = hasRequiredScopes("createLicense", ["license:write"]);Common Mistakes
- creating every automation key with
admininstead of narrowing it - assuming a route named
GETmust always use a read scope - forgetting that runtime routes use a different auth header entirely
- debugging
TOKEN_SCOPE_DENIEDwithout checking the exact operation inapi/openapi.yaml