API keys
Use the publishable half in image URLs, keep the secret half on your server, and restrict where public requests may originate.
Every key is a pair of credentials with opposite jobs.
| Half | Looks like | Goes in | Authenticates |
|---|---|---|---|
| Publishable | pk_… | An image URL | Image API |
| Secret | sk_… | A server-side Authorization header | Data API |
Put the publishable half in image URLs
It appears in page source by design. Protect it with an origin allowlist, a burst limit, and the monthly allowance attached to its product.
<img
src="https://cdn.gymassets.dev/v1/pk_…/body/male/front.webp?primary=pectorals"
alt="Chest muscles highlighted"
/> An origin allowlist is exact by origin: scheme, hostname, and port. Paths are not
part of an origin. Requests from an unlisted origin are refused with
403 origin_not_allowed before the render. A refused request is never counted.
The image host reads Origin when it is present and falls back to Referer, reduced
to its origin. A plain <img> sends no Origin header.
Both headers are set by the client. The allowlist stops a stranger who copied your publishable key out of a page from rendering against your account. It is not authentication, and nothing further should be built on it.
Keep the secret half on your server
curl 'https://api.gymassets.dev/v1/equipment' \
-H "Authorization: Bearer $GA_SECRET_KEY" A publishable key sent to the data API returns 401 wrong_credential rather than
401 unauthenticated.
Rotate without an outage
Rotation creates a fresh pair while the old one remains valid. Deploy the new pair, then revoke the old pair. Revocation affects both halves, including image URLs that still contain the old publishable key.