Image Serving & Transforms
Authenticated image proxy
What it does
GET /api/v1/images/{bucket}/{object_key} streams an image from S3 through the backend, with:
- JWT authentication (same permission check as
read) - Content-type allow-list:
jpeg,png,gif,webp,svg,bmp,tiff,avif. Anything else returns 415 Unsupported Media Type — this prevents the endpoint from being abused as a generic file proxy. Cache-Control: public, max-age=3600headers for browser caching- Streaming response (no full buffer in memory) when no transform is requested
This is used by the in-app image preview modal so previews work even on private buckets.
On-the-fly transformation
Add any of these query params to resize or re-encode the image without storing a second copy (also available on public share links):
| Param | Meaning | Example |
|---|---|---|
w / h | Target width / height in px (aspect preserved when only one given) | ?w=1024 |
format | Output format: webp, jpeg, png | ?format=webp |
q | Quality 1–100 (applies to webp/jpeg) | ?q=80 |
fit | contain (default, fits inside box) or cover (fills + center-crops) | ?fit=cover |
curl "http://localhost:8200/api/v1/images/products/sku-12345.png?w=512&format=webp&q=80" \
-H "Authorization: Bearer $TOKEN" -o thumb.webp
When a transform is requested the object is buffered in memory and processed with Pillow; sources larger than MAX_IMAGE_TRANSFORM_MB (default 25) return 413, and non-raster/undecodable sources (e.g. SVG) return 415. Without transform params, the original streaming path is used unchanged.
Why this matters for LLMs: shipping a 4000×3000 product photo to a multimodal model wastes tokens and latency.
?w=1024&format=webp&q=80hands the model a right-sized image straight from the share URL — no pre-processing pipeline, no second stored asset.
How to use
In the UI: click any image file — the preview modal opens, fetching from /api/v1/images/... with the user's JWT.
Programmatic:
curl http://localhost:8200/api/v1/images/marketing-assets/logos/hero.png \
-H "Authorization: Bearer $TOKEN" \
-o hero.png
Use case: Embedding images in an internal dashboard
You're building an internal Grafana-style dashboard and want to embed product photos pulled from a private S3 bucket. Rather than making the bucket public or wiring up presigned URLs that expire, the dashboard's frontend (already authenticated to s3BEAR) hits the image proxy directly:
<img src="https://s3bear.example.com/api/v1/images/products/sku-12345.jpg"
crossorigin="use-credentials" />
Permissions are enforced per-user, the URL never expires, and you get free browser caching.
For public-facing URLs — like ones you hand to an LLM API or an external partner — use Public Share Links instead, which also accept the same transform params documented above.
