QFind anything/
API Reference

API Keys

Create long-lived API keys (publicId.secret, Argon2id-hashed) for programmatic access via X-Api-Key or Bearer.

API keys are long-lived credentials for service-to-service calls, scripts, or background jobs. Unlike JWTs, they do not expire quickly unless you set expiresAt. Use them when a user is not interactively present (cron jobs, internal services, CI/CD calling this API).

The server stores only an Argon2id hash of the secret segment. The full key string is shown once at creation.

Key format

Each key is a single string with two segments separated by the first dot:

  • publicId — Starts with pr_, then a random URL-safe segment. Used for database lookup (not secret).
  • secret — High-entropy random segment (base64url). Proves possession; never stored in plaintext.

Example shape (values are illustrative):

pr_<randomPublic>.<randomSecret>

Tenant and environment are not embedded in the string. They are bound to the key in the database and must be sent explicitly in headers (see below).

Lifecycle

  1. CreatePOST /auth/api-keys with a JWT (not an API key). Body: name, optional permissions, optional expiresAt (ISO 8601).
  2. Store — Response includes apiKey (full string), id (UUID), and publicId. Save apiKey in a secret manager; it cannot be retrieved again.
  3. Use — Send the key in X-Api-Key or as Authorization: Bearer <apiKey> (opaque token, not a JWT). Always send X-Tenant-Id and X-Environment; they must match the key’s tenant and environment.
  4. ListGET /auth/api-keys with a JWT returns metadata for keys in the current tenant/environment (id, publicId, name, permissions, expiresAt, revokedAt, etc.). Never returns the secret.
  5. RevokeDELETE /auth/api-keys/:id with a JWT sets revokedAt. Revoked keys reject all API requests.

Create, list, and revoke are JWT-only so automation cannot mint or revoke keys without a user session (or equivalent).

Permissions

Default permissions are ['read', 'write']. You can pass a custom array (e.g. ['read'] for read-only).

For API key authentication, the API enforces:

  • GET, HEAD, OPTIONS — require permission read.
  • POST, PUT, PATCH, DELETE, and other methods — require permission write.

JWT and Keycloak users are not restricted by this permission list on these routes (they use roles and other guards where applicable).

Expiry

expiresAt is optional. If set, the API rejects the key after that time with an authentication error.

Request parameters (create)

Parameters

name(string)required

Display name for the API key.

permissions(array)

Permissions (e.g. read, write). Default: ['read', 'write'].

expiresAt(string)

ISO 8601 expiry date. Optional.

Calling the API with a key

Prefer X-Api-Key so the key is not confused with a JWT:

X-Api-Key: pr_xxxxxxxx.<secret>
X-Tenant-Id: 123e4567-e89b-12d3-a456-426614174000
X-Environment: production

If both X-Api-Key and Authorization are present, X-Api-Key takes precedence for choosing the credential.

Swagger

The API docs register both Bearer and X-Api-Key. You can authorize with either.

Migrations and breaking changes

Database migrations that replace the legacy key storage invalidate previously issued keys. After upgrading, create new keys with POST /auth/api-keys.