Packages
Key management service with embedded OTP runtime, optional HTTP API, SQLite/PostgreSQL storage, and external RMK providers
Current section
Files
Jump to
Current section
Files
docs/http-api.md
# HTTP API
`KMS.API` exposes a minimal JSON API for backend KMS clients.
This API is an admin/backend surface. Do not expose it directly to browsers or the public internet.
Most applications should use `KMS.Client.Remote` instead of hand-writing HTTP calls.
## Authentication
Health endpoints do not require a token.
All `/api/*` endpoints require:
```text
Authorization: Bearer <KMS_API_TOKEN>
```
If `config :kms, :api` has no `:api_token`, API routes fail closed:
```json
{"error":"api_token_required"}
```
## Common request shape
Most POST bodies are JSON objects.
Operations that accept options use an `opts` object:
```json
{
"alias": "owner:alice",
"cleartext": "secret",
"opts": {"aad": "document:123/body"}
}
```
`opts.session` may carry a KMS session secret for principal-scoped authorization.
## Common responses
Success returns `200` with an operation-specific JSON key.
Errors return JSON:
```json
{"error":"not_found"}
```
Validation errors return:
```json
{"error":"invalid_changeset","details":{}}
```
Common statuses:
| Status | Meaning |
|---:|---|
| 200 | Success |
| 400 | Invalid JSON/body shape |
| 401 | Missing or wrong API token |
| 404 | Not found |
| 422 | Invalid changeset |
| 503 | API token missing or readiness failed |
## Health
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | `/health` | no | Cheap compatibility check. |
| GET | `/health/live` | no | Liveness check. |
| GET | `/health/ready` | no | Readiness check for DB, RMK access, and API token config. |
## Encryption
| Method | Path | Body | Response |
|---|---|---|---|
| POST | `/api/encrypt` | `alias`, `cleartext`, `opts` | `encrypted` |
| POST | `/api/decrypt` | `alias`, `encrypted`, `opts` | `cleartext` or `cleartexts` |
| POST | `/api/rmk_pdk/encrypt` | `cleartext`, `secret`, `opts` | `encrypted` |
| POST | `/api/rmk_pdk/decrypt` | `encrypted`, `secret`, `opts` | `cleartext` |
Example:
```sh
curl -fsS \
-H "authorization: Bearer $KMS_API_TOKEN" \
-H "content-type: application/json" \
-d '{"alias":"owner:alice","cleartext":"secret","opts":{"aad":"document:123/body"}}' \
https://kms.internal.example.com/api/encrypt
```
## KEKs
| Method | Path | Body | Response |
|---|---|---|---|
| POST | `/api/keks/create` | `alias`, `opts` | `kek` |
| POST | `/api/keks/tags` | `alias`, `opts` | `tags` |
| POST | `/api/keks/aliases_by_tag` | `tag`, `opts` | `aliases` |
| POST | `/api/keks/add_tags` | `alias`, `tags`, `opts` | `tags` |
| POST | `/api/keks/remove_tags` | `alias`, `tags`, `opts` | `tags` |
| POST | `/api/keks/rewrap_for_principal` | `alias`, `target_kind`, `target_ref`, `opts` | `ok` |
| POST | `/api/keks/rewrap_for_passphrase` | `alias`, `passphrase`, `opts` | `wrapping_id` |
| POST | `/api/keks/revoke_passphrase` | `alias`, `wrapping_id`, `opts` | `ok` |
KEK metadata includes `protection: "rmk" | "session"`, never key material. New aliases created with `opts.session` are session-protected. Passphrase sharing/revocation requires the principal's active session, `kek.rewrap` permission, and a usable recipient envelope. See [Factor-bound aliases](use_cases/factor_bound_aliases.md) for the complete flow and compatibility limits.
## Principals
| Method | Path | Body | Response |
|---|---|---|---|
| POST | `/api/principals/get` | `kind`, `ref`, `opts` | `principal` |
| POST | `/api/principals/list` | `opts` | `principals` |
| POST | `/api/principals/create` | `attrs`, `opts` | `principal` |
| POST | `/api/principals/update` | `kind`, `ref`, `attrs`, `opts` | `principal` |
| POST | `/api/principals/delete` | `kind`, `ref` | `principal` |
When `opts.session` is supplied to principal creation, it must authorize `principal.create` against the new principal's reference/tags. Omitting it remains trusted bootstrap/admin execution; a malformed supplied session is not treated as absent.
## Principal factors
| Method | Path | Body | Response |
|---|---|---|---|
| POST | `/api/principal_factors/get` | `id` | `principal_factor` |
| POST | `/api/principal_factors/list` | `kind`, `ref` | `principal_factors` |
| POST | `/api/principal_factors/create` | `kind`, `ref`, `attrs` | `principal_factor` |
| POST | `/api/principal_factors/update` | `id`, `attrs` | `principal_factor` |
| POST | `/api/principal_factors/delete` | `id` | `principal_factor` |
## Bindings
| Method | Path | Body | Response |
|---|---|---|---|
| POST | `/api/bindings/get` | `id` | `binding` |
| POST | `/api/bindings/list` | `principal_id` | `bindings` |
| POST | `/api/bindings/create` | `principal_id`, `attrs` | `binding` |
| POST | `/api/bindings/update` | `id`, `attrs` | `binding` |
| POST | `/api/bindings/delete` | `id` | `binding` |
## Fallback recovery
Fallback operations are absent from the compiled HTTP router. This includes public-key registry, envelope metadata, and private-key operations. Use trusted local Elixir calls or a controlled remote shell on the KMS host. See [Fallback recovery](fallback-recovery.md).
## Sessions
| Method | Path | Body | Response |
|---|---|---|---|
| POST | `/api/sessions/get` | `secret` | `session` |
| POST | `/api/sessions/active` | `secret` | `session` |
| POST | `/api/sessions/list` | `kind`, `ref` | `sessions` |
| POST | `/api/sessions/create` | `kind`, `ref`, `attrs`, `opts` | `session` |
| POST | `/api/sessions/passphrase` | `attrs` | `session` |
| POST | `/api/sessions/advance` | `secret`, `attrs` | `session` |
| POST | `/api/sessions/nudge` | `secret`, `opts` | `session` |
| POST | `/api/sessions/delete` | `secret` | `session` |
| POST | `/api/sessions/delete_all` | `kind`, `ref`, `opts` | `sessions` |
| POST | `/api/sessions/refresh` | `secret`, `opts` | `session` |
Session response JSON redacts bearer secrets in inspect-like contexts, but HTTP session creation returns the session secret because callers need it. Treat it like a password.
## WebAuthn
| Method | Path | Body | Response |
|---|---|---|---|
| POST | `/api/webauthn/registration/begin` | `kind`, `ref`, `opts` | challenge |
| POST | `/api/webauthn/registration/finish` | `challenge_id`, `response`, `opts` | credential |
| POST | `/api/webauthn/authentication/begin` | `kind`, `ref`, `opts` | challenge |
| POST | `/api/webauthn/authentication/finish` | `challenge_id`, `response`, `opts` | session |
See [WebAuthn](factors/webauthn.md).
## Security rules
- Use TLS or trusted private networking.
- Keep API tokens high entropy.
- Do not log request or response bodies.
- Do not log bearer tokens, plaintext, ciphertext payloads, passwords, factor codes, or RMK material.
- Put authorization in your application and/or use KMS sessions/bindings.