> For the complete documentation index, see [llms.txt](https://docs.kangal.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kangal.dev/admin-api/auth-pagination-errors.md).

# Authentication, pagination, and errors

## User access tokens

Create a user session with `POST /auth/login`:

```bash
curl -fsS -X POST \
  -H 'Content-Type: application/json' \
  "$KANGAL_URL/auth/login" \
  -d '{
    "username": "admin@example.com",
    "password": "REDACTED",
    "tenant_id": "tenant-acme"
  }' | jq
```

The response includes `access_token`, `token_type`, `expires_in`, and `refresh_token`. Keep both tokens out of source control and logs. User access JWTs are required by the current audit-list route and are also accepted by standard Admin API dependencies.

## Admin API tokens

Admin API tokens are machine credentials. Create one with an authenticated admin writer:

```bash
curl -fsS -X POST \
  -H "Authorization: Bearer $ADMIN_ACCESS_TOKEN" \
  -H 'Content-Type: application/json' \
  "$KANGAL_URL/api/v1/admin/api-tokens" \
  -d '{
    "name": "production-readonly-exporter",
    "tenant_id": "tenant-acme",
    "scopes": ["admin:read"]
  }' | tee token-create.json | jq
```

The secret starts with `kangaladm_` and is returned in plaintext only in this create response. Kangal stores its hash and visible prefix, not a retrievable plaintext value. Put the token into the authorized secret manager immediately and remove the response artifact.

Supported scope behavior:

| Scope            | Effect                                  |
| ---------------- | --------------------------------------- |
| `admin:read`     | GET, HEAD, and OPTIONS Admin API calls. |
| `admin:write`    | Write calls and read calls.             |
| `admin:*` or `*` | Full Admin API method scope.            |

The default scope is read. A read-only token is represented as a read-only admin role; a writer token as an admin role. Revoked or expired tokens fail authentication.

A regular admin can create tenant-scoped credentials within their authority. Only a super administrator can create a global super-admin credential. Prefer one token per workload, tenant, and environment; assign an expiry, rotate it, and revoke it when the workload is retired.

## Method-aware role checks

For routes using the standard admin dependency:

| HTTP methods                     | Accepted roles                                              |
| -------------------------------- | ----------------------------------------------------------- |
| `GET`, `HEAD`, `OPTIONS`         | `admin`, `super_admin`, `admin_readonly`, `read_only_admin` |
| `POST`, `PUT`, `PATCH`, `DELETE` | `admin`, `super_admin`                                      |

Token scope and role must both permit the method. Route-specific RBAC can add another requirement; observability adds `observability:read` or `observability:write` from the tenant permission matrix.

Be aware that an operation's semantic intent does not change its HTTP permission. Configuration validate, diff, dry-run, snapshot creation, and rollback preview are `POST` requests and therefore require write access.

## Bearer usage

```http
Authorization: Bearer kangaladm_...
```

Do not pass credentials in query parameters. Use TLS, redact authorization headers in proxies, and avoid shell tracing (`set -x`) around token-bearing commands.

## Shared list pagination

Many resource lists use:

| Parameter       | Behavior                                                  |
| --------------- | --------------------------------------------------------- |
| `limit`         | Page size, normally capped at 1,000 by the shared helper. |
| `offset`        | Zero-based offset; must be non-negative.                  |
| `sort`          | Endpoint-specific allow-listed field.                     |
| `order`         | `asc` or `desc`.                                          |
| `labelSelector` | Optional resource label filter on supporting routes.      |

Responses from the shared helper include:

```http
X-Total-Count: 248
X-Limit: 100
X-Offset: 0
```

```bash
curl -fsS -G \
  -D /tmp/kangal-headers.txt \
  -H "Authorization: Bearer $KANGAL_TOKEN" \
  --data-urlencode 'tenant_id=tenant-acme' \
  --data-urlencode 'limit=100' \
  --data-urlencode 'offset=0' \
  --data-urlencode 'sort=name' \
  --data-urlencode 'order=asc' \
  --data-urlencode 'labelSelector=environment=production' \
  "$KANGAL_URL/api/v1/admin/gateways/gw-production/services" | jq

grep -Ei '^x-(total-count|limit|offset):' /tmp/kangal-headers.txt
```

Pagination is not universal. Check the endpoint schema:

* Gateway lists do not use the shared pagination helper.
* Routes use shared pagination but do not expose `labelSelector`.
* Audit uses `skip` (default 0), `limit` (default 50, maximum 200), and `sort_direction`; it returns `X-Total-Count`.
* Snapshot list uses `limit` (default 20, maximum 100) and returns a plain array.
* Observability request/anomaly searches cap `limit` at 500; live polling caps it at 200 and uses a signed cursor.
* SLO timeline caps `limit` at 500.

Do not build one generic paginator without endpoint metadata. For changing datasets, offset pagination can duplicate or skip items; use a stable supported sort and de-duplicate by resource ID when necessary.

## Label selectors and sorting

Pass `labelSelector` exactly as documented by a supporting endpoint. A malformed selector returns a client error. Sort fields are allow-listed per resource, so a field accepted by services may not be accepted by targets or certificates.

Discover query parameters from OpenAPI:

```bash
curl -fsS "$KANGAL_URL/openapi.json" \
  | jq '.paths["/api/v1/admin/gateways/{gateway_id}/services"].get.parameters'
```

## Error shape

FastAPI errors generally use a `detail` member:

```json
{
  "detail": "Missing authorization token"
}
```

Request-model validation (`422`) uses a list of field errors:

```json
{
  "detail": [
    {
      "type": "missing",
      "loc": ["body", "name"],
      "msg": "Field required",
      "input": {}
    }
  ]
}
```

Configuration parse and domain-validation responses can add their own structured validation, diff, count, or error data. Log the full response body under access controls, while redacting tokens and sensitive configuration.

## Status codes

| Code  | Meaning and first check                                                                                    |
| ----- | ---------------------------------------------------------------------------------------------------------- |
| `200` | Successful read/update or operation result.                                                                |
| `201` | Resource/event created.                                                                                    |
| `204` | Successful operation with no response body.                                                                |
| `400` | Malformed query/body, invalid cursor, parse error, tenant mismatch, or domain precondition. Read `detail`. |
| `401` | Missing, malformed, invalid, expired, or revoked bearer token.                                             |
| `403` | Authenticated but role, scope, permission, or tenant access is insufficient.                               |
| `404` | Resource not visible/found in the applicable tenant scope.                                                 |
| `409` | Conflicting resource or state when exposed by the endpoint.                                                |
| `422` | Request schema/field validation failed.                                                                    |
| `429` | Rate limit exceeded. Respect retry guidance where present.                                                 |
| `500` | Unhandled server failure. Capture request ID and inspect API logs.                                         |
| `503` | Service/readiness or dependency unavailable. Check `/ready` and dependencies.                              |

For security, `404` can intentionally avoid revealing whether a cross-tenant resource exists. Do not switch tenants or broaden credentials merely to distinguish it from absence.

## Robust error handling

```bash
response=$(mktemp)
headers=$(mktemp)

code=$(curl -sS \
  -D "$headers" \
  -o "$response" \
  -w '%{http_code}' \
  -H "Authorization: Bearer $KANGAL_TOKEN" \
  -H 'X-Request-ID: support-case-8472' \
  "$KANGAL_URL/api/v1/admin/gateways/gw-production/services?tenant_id=tenant-acme") || {
    echo 'Network or TLS failure' >&2
    exit 1
  }

case "$code" in
  2??)
    test -s "$response" && jq . "$response"
    ;;
  401)
    echo 'Refresh/login or rotate the token; do not retry unchanged credentials.' >&2
    jq . "$response" >&2
    exit 1
    ;;
  403)
    echo 'Check method role, token scope, tenant, and route permission.' >&2
    jq . "$response" >&2
    exit 1
    ;;
  429|503)
    echo "Transient response HTTP $code; apply bounded backoff where operation is safe." >&2
    jq . "$response" >&2
    exit 1
    ;;
  *)
    echo "Kangal API failed with HTTP $code" >&2
    jq . "$response" 2>/dev/null || cat "$response" >&2
    exit 1
    ;;
esac
```

## Retry rules

* Retry GET requests on connection failure, `429`, or `503` with bounded exponential backoff and jitter.
* Honor `Retry-After` when present.
* Do not automatically retry create/import/sync/rollback after timeout. First read or export live state to determine whether it applied.
* Reusing `X-Request-ID` helps investigation but does not make a write idempotent.
* For cursor polling, follow the endpoint's `poll_after_ms`, `has_more`, `gap_detected`, `cursor_expired`, and `next_cursor` fields instead of a generic retry loop.

## Troubleshooting authorization

1. Confirm the header is present and uses the `Bearer` scheme.
2. Confirm the token belongs to the current API environment and is not expired/revoked.
3. Compare the HTTP method with the role table.
4. For Admin API tokens, inspect whether scope is `admin:read`, `admin:write`, or wildcard.
5. Confirm tenant assignment and explicit `tenant_id`.
6. Check route-specific permission such as `observability:read`.
7. For `/admin/audits/`, use a user access JWT from `/auth/login`.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.kangal.dev/admin-api/auth-pagination-errors.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
