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=3600 headers 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):

ParamMeaningExample
w / hTarget width / height in px (aspect preserved when only one given)?w=1024
formatOutput format: webp, jpeg, png?format=webp
qQuality 1–100 (applies to webp/jpeg)?q=80
fitcontain (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=80 hands 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.