> ## Documentation Index
> Fetch the complete documentation index at: https://docs.blindcast.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Key Server Overview

> Reference key server as a Docker image. Pull, configure, and run — handles key derivation, authentication, leases, and presigned URLs.

The BlindCast key server is a Docker image that handles everything your player and uploader need: derive content keys, authenticate viewers, manage leases, and generate presigned upload URLs.

<Note>
  **Looking for the full server?** The standalone key server documented here derives keys for any content ID you request. The [BlindCast Server](/server/overview) adds a content registry, API keys, an admin dashboard, and only derives keys for registered content. Use the full server for new deployments; use the standalone key server if you only need key derivation and manage content IDs yourself.
</Note>

## Quick start

```bash theme={null}
docker run -d \
  -e MASTER_KEY_HEX=<your-master-key> \
  -e SALT_HEX=<your-salt> \
  -e CORS_ORIGINS=https://your-app.com \
  -p 4100:4100 \
  blindcast/keyserver
```

Generate a master key and salt with the [CLI](/cli/keygen):

```bash theme={null}
blindcast keygen
# BLINDCAST_MASTER_KEY=a1b2c3...
# BLINDCAST_SALT=f6e5d4...
```

## Endpoints

| Method | Path                      | Description                   |
| ------ | ------------------------- | ----------------------------- |
| `GET`  | `/keys/:contentId`        | Content key (16 raw bytes)    |
| `GET`  | `/keys/:contentId/:epoch` | Epoch key (for key rotation)  |
| `POST` | `/keys/leases`            | Create a lease                |
| `POST` | `/keys/leases/renew`      | Renew a lease                 |
| `POST` | `/presign`                | Get a presigned S3 upload URL |
| `GET`  | `/health`                 | Health check                  |

## What it does

```mermaid theme={null}
graph LR
  Player["Player<br/>(viewer's browser)"]
  Uploader["Uploader<br/>(creator's browser)"]
  KS["Key Server<br/>(Docker)"]
  S3["S3"]

  Player -->|GET /keys/:contentId| KS
  KS -->|HKDF derive| KS
  KS -->|content key| Player

  Uploader -->|POST /presign| KS
  KS -->|presigned URL| Uploader
  Uploader -->|PUT encrypted bytes| S3
```

1. **Key derivation:** Derives per-content keys from the master key using HKDF-SHA-256
2. **Authentication:** Validates JWTs before issuing keys (configurable via env vars)
3. **Leases:** Time-limited access tokens that can be revoked server-side
4. **Presign:** Generates presigned S3 URLs for the browser uploader

## Configuration at a glance

| Env var           | Required | Description                                            |
| ----------------- | -------- | ------------------------------------------------------ |
| `MASTER_KEY_HEX`  | Yes      | Master key as hex (from `blindcast keygen`)            |
| `SALT_HEX`        | Yes      | Salt as hex (from `blindcast keygen`)                  |
| `CORS_ORIGINS`    | Yes      | Allowed CORS origin(s)                                 |
| `AUTH_JWT_SECRET` | No       | HS256 JWT secret for auth                              |
| `AUTH_JWKS_URL`   | No       | JWKS URL for RS256/ES256 auth                          |
| `ENABLE_PRESIGN`  | No       | Enable presign endpoint (`true`/`false`)               |
| `DATABASE_URL`    | No       | Postgres URL (default: SQLite at `/data/blindcast.db`) |

See [Configuration](/key-server/configuration) for the full reference.

## Next steps

* [Configuration](/key-server/configuration) — env vars, auth, CORS
* [Database](/key-server/database) — SQLite vs. Postgres
* [Presign Endpoint](/key-server/presign) — enable browser uploads
* [Leases](/key-server/leases) — revoke access without re-encrypting
