Authentication
Authentication is optional and configured by environment variables. Exactly one mechanism is active at a time:
- Static API Key — active when
API_KEYis set (and JWT is not). - JWT (JWKS) — active when
JWT_ISSUERandJWT_JWKS_URLare both set. - Public — when neither is configured, the API is open.
JWT takes precedence over the API key when both are configured. Authentication guards the
conversion, rendering, validation, and identification endpoints; /health, the template schema,
and the API docs stay public. Failed or missing credentials return 401.
API KEY
Section titled “API KEY”Run the container with the API_KEY set:
docker run -p 8080:8080 \ -e API_KEY="super-secret-key" \ ghcr.io/bambamboole/pdf-ua-api:latestThen send it as a Bearer token:
curl -X POST http://localhost:8080/convert \ -H "Authorization: Bearer super-secret-key" \ -H "Content-Type: application/json" \ -d '{"html":"<html lang=\"en\"><head><title>Doc</title></head><body><h1>Hi</h1></body></html>"}' \ --output out.pdfJWT (JWKS)
Section titled “JWT (JWKS)”The API only verifies tokens; it never issues them. Configure:
JWT_ISSUER— expectedissand the JWKS issuerJWT_JWKS_URL— the issuer’s JWKS endpoint (public keys, RS256)JWT_AUDIENCE— optional; when set, theaudclaim must match
The signature, issuer, and expiry are always checked; the audience is checked only when
JWT_AUDIENCE is set. Send the token as Authorization: Bearer <token>.
Run the container configured to verify tokens from your issuer:
docker run -p 8080:8080 \ -e JWT_ISSUER="https://auth.example.com/" \ -e JWT_JWKS_URL="https://auth.example.com/.well-known/jwks.json" \ -e JWT_AUDIENCE="pdf-ua-api" \ ghcr.io/bambamboole/pdf-ua-api:latestOmit JWT_AUDIENCE to skip the audience check. The API reaches the JWKS URL to fetch the
issuer’s public keys, so the container needs network access to it.
Then send it as a Bearer token:
curl -X POST http://localhost:8080/convert \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{"html":"<html lang=\"en\"><head><title>Doc</title></head><body><h1>Hi</h1></body></html>"}' \ --output out.pdfRejected requests
Section titled “Rejected requests”A missing or invalid credential returns 401 Unauthorized and the request never reaches the
renderer:
curl -i -X POST http://localhost:8080/convert \ -H "Content-Type: application/json" \ -d '{"html":"<h1>Hi</h1>"}'# HTTP/1.1 401 UnauthorizedThe public endpoints (/health, the template schema, and the API docs) stay reachable without
credentials.