What you will do
- Everything except the public routes needs
Authorization: Bearer <token>. - Three token kinds reach the same surface: a session access token, a personal access token, and a service account token.
- A system that calls the API should hold a service account token, not a token minted from a person's account.
- Token values are returned once, at creation. There is no route that reads one back.
- The
nopsaiCLI drives the same routes with the same authorization: it adds no server behaviour of its own. - Install the CLI from the latest GitHub Release assets before using CLI examples; future CLI upgrades are
nopsai update --version <x.y.z>.
Before you start
- A reachable API
- The API address,
http://localhost:8080on a local installcurl -s "$NOPSAI_URL/livez" - Credentials
- A local account, or an existing personal or service account token
- Tools
curlandjq, or the releasednopsaiCLI fromhttps://github.com/nopsai/nopsai/releases/latestcurl --version && jq --version
Steps
- 01
Get a token
Logging in gives a short-lived access token. For anything automated, exchange it once for a personal access token — or better, use a service account.
Important- The first login of the bootstrap administrator must rotate its password before other routes will answer.
Log in and mint a personal tokenbash ACCESS=$(curl -sX POST "$NOPSAI_URL/v1/auth/login" \ -H "Content-Type: application/json" \ -d "{\"identifier\":\"[email protected]\",\"password\":\"$PASSWORD\"}" | jq -r .access_token) curl -sX POST "$NOPSAI_URL/v1/auth/personal-tokens" \ -H "Authorization: Bearer $ACCESS" \ -H "Content-Type: application/json" \ -d '{"name":"integration"}' | jqExpected result- A token value, returned once. Store it where you keep other credentials.
- 02
Confirm who you are
This is the fastest way to tell an authentication problem from an authorization one.
Read the current identitybash curl -s -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/auth/me" | jqExpected result- The identity, its roles, and its effective capabilities. A 401 here means the token is wrong; a 403 elsewhere means the token is right and the access is not.
- 03
Call a route
Every authenticated route follows the same shape, so one working call generalises.
List runsbash curl -s -H "Authorization: Bearer $NOPSAI_TOKEN" "$NOPSAI_URL/v1/runs?limit=5" | jq '.[] | {run_id, pipeline_name, status}'Verify- A JSON array comes back, filtered to what this caller is allowed to see.
- 04
Ask for JSON when a route can answer either way
A few routes answer with plain text unless the request asks for JSON. Starting a run is the one most integrations hit first.
Start a run and read the run IDbash curl -sX POST "$NOPSAI_URL/v1/run/first-pipeline" \ -H "Authorization: Bearer $NOPSAI_TOKEN" \ -H "Accept: application/json" \ -H "Content-Type: application/json" \ -d '{"scope":"platform/production"}' | jq -r .run_idExpected result- Without
Accept: application/jsonthe same call returnsPipeline run created successfully with ID: <uuid>as text.
- Without
- 05
Use the CLI when you would rather not hand-roll requests
The CLI carries a generated route catalogue that is parity-tested against the registered routes, so it cannot drift from the API. Install it from the latest GitHub Release archive, extract the binary onto PATH, and remove the archive before using these commands.
The same calls through the CLIbash nopsai context add local --api "$NOPSAI_URL" NOPSAI_TOKEN=nopat_<secret> nopsai api request GET /v1/runs nopsai api call GET '/v1/runs/{runID}' --path runID=<run-id> nopsai api routes --output json
How it works
Authorization is resolved per resource, not per route. Two callers hitting the same list endpoint can legitimately receive different rows, because AAA filters the result to what each may see.
A 401 is about the token: missing, expired, or malformed. A 403 is about the caller: the token is valid and the action is not permitted on that resource. Treat them as different bugs.
Public routes are the exception rather than the rule: the platform probes, the setup routes, login and token refresh, the OIDC and OAuth2 callbacks, provider webhook ingress, and the runner bootstrap download.
Implementation evidence
services/nopsai/routes.goThe registered route surface and its middleware chain.
doc/jwt-authentication.mdToken kinds, claims, refresh, and service tokens.
internal/cli/apicatalog/catalog.goGenerated route catalogue the CLI drives.

