Skip to content

Issue an API Credential

What this is: minting (or revoking) a machine ingest credential — the bearer token an external producer uses to push force-tracking data into the deployment over the HTTP /api/feed/* API. When you'd do it: wiring up NiFi or an external force-tracking source that POSTs detections or targets, or cutting one off. How long it takes: about two minutes to mint; revoking is instant.

Who can do this: an Admin. The API-credentials screens are session- and admin-guarded — they only show up if your own login has the Admin role. A normal Operator login won't see them.

This is a machine-to-machine credential — a separate trust root from operator, device, and server identity. It is an HS256 JWT verified against a database registry, not a Directory-signed identity, and it carries no clearance. For the full wire contract see Machine Ingest API. You'll do everything on the admin website — no command line for minting or revoking.

The shape of it

flowchart LR
    A["Open the<br/>API Credentials page"] --> B["Choose scopes<br/>and operations"]
    B --> C["Create — copy the<br/>token (shown once)"]
    C --> D["Hand it to the<br/>producer (NiFi / source)"]

You pick what the token may do, the page hands you the token once, and you pass it securely to whoever is configuring the producer.

Before you start

  • You're signed in to the admin site as an Admin.
  • The signing secret is set. WAYPOINT_API_JWT_SECRET must be set on the web tier — the app fails closed at boot without it, and tokens can't be verified without it. See the env table in Stand up the web client.
  • You know what the producer needs to do — which scopes (detections:write / detections:read / targets:write / targets:read) and which operations (specific operation ids, or account-wide *).
  • A secure way to hand the token to whoever is configuring the producer.

Mint a credential

  1. Open the API Credentials page. Navigate to /admin/api-credentials. You'll see the list of live credentials and a control to create a new one.

  2. Choose the scopes. Tick the capability set the producer needs — detections:write to push detection rows, targets:write to push target rows, and the …:read scopes for read access. A token is rejected with 403 at any endpoint whose scope it lacks, so grant only what the producer uses.

  3. Choose the operations (ops). Either name specific operation ids, or set it account-wide with *. This is an independent axis from scopes and is checked per row against the operation_id the row carries — an empty ops list is deny-all.

  4. Set an expiry (optional). Add a hard expiry if the credential should age out on its own; leave it blank for no expiry.

  5. Create — and copy the token now. On create, the token is shown once via a flash message. Copy it immediately — it is never re-retrievable; the system stores only metadata (the kid, scopes, ops), never the secret. If you navigate away without copying it, you must revoke it and mint a fresh one.

  6. Hand it off. Pass the token securely to whoever is configuring the producer (NiFi, an external force-tracking source). They set it as the Authorization: Bearer <token> on their /api/feed/* requests.

Revoke a credential

  1. On the API Credentials page, find the credential and delete it (DELETE /admin/api-credentials/:id).
  2. Revocation is effective from the next request: the JWT signature still verifies (the signing secret is unchanged), but the live lookup of its kid in the registry now fails, so the credential is dead. There is no un-revoke — to restore access, mint a fresh credential.

Rotating the signing secret is the blunt instrument. Rotating WAYPOINT_API_JWT_SECRET invalidates all outstanding ingest tokens at once, with no overlap window — distinct from Directory signing-key rotation, which keeps the previous key served until its tokens expire (see Rotate keys). Use per-credential revoke for a single producer; rotate the secret only when you mean to cut everything off.

How to know it worked

  • Mint: a POST /api/feed/detections (or /api/feed/targets) with the bearer token returns { accepted, rejected }.
  • Scope check: a token lacking the endpoint's scope returns 403.
  • Revoke / expiry: a revoked or expired token returns 401 on the next request.

If something goes wrong

  • You navigated away before copying the token. It's gone — it was shown once only. Revoke the credential on the API Credentials page and mint a fresh one.
  • The producer gets 401 on every request. Either the token is revoked/expired, or the web tier has no (or a different) WAYPOINT_API_JWT_SECRET than the one the token was signed with — check the env on the web tier.
  • The producer gets 403. The token's scopes don't include the endpoint's required scope. Mint a new credential with the right scope; you cannot widen an existing token's scopes.
  • Rows are rejected with a 404 / unknown operation. The token's ops allowlist doesn't cover the operation_id the rows carry, or that operation id doesn't exist.

See also


Verified against web@feature/roadmap — admin UI /admin/api-credentials (session + admin guarded); credential registry, findByKidLive, and revoke in web/app/domains/api_credentials/; bearer verify and scope enforcement in web/app/middleware/api_auth_middleware.ts; per-row ops check in web/app/domains/api/. The token is shown once on create and never stored at rest.