API Keys & Security

Two keys, how to rotate them without downtime, and what to do when one leaks.

The two keys

Client keySecret key
ReturnsPublished content onlyPublished and draft content
Can writeNoYes
Where it belongsBrowser, mobile app, static site buildServer-side only

Neither key is a secret you can be careless with.

The Client key is designed to survive being seen (it reads published content and nothing else), so shipping it in a JavaScript bundle is expected and safe. That is not the same as publishing it deliberately. Anyone holding it can read your published content and spend your rate limit, so keep it out of public repositories and rotate it if it escapes. The Secret key must never reach a browser under any circumstances.

Rotating a key without downtime

Rotation runs in two steps so there is never a moment when no valid key exists. Both keys work during the overlap, for as long as you need.

  1. 1

    Generate a secondary key

    Nothing changes for your site. The existing key keeps working exactly as before.

  2. 2

    Deploy the secondary key

    Update your site and ship it. Take as long as you like. Both keys are accepted while the secondary exists, so a slow rollout costs nothing.

  3. 3

    Promote

    The secondary becomes the only key and the old one stops working immediately. Promote once you have confirmed nothing is still calling with the old key.

What a straggler sees after you promote

Anything still sending the old key gets 401 on the next request, not stale content and not a slow failure. If that is a live site, it stops rendering CMS content until it is redeployed with the new key. This is the one step of rotation you cannot undo by clicking again, so confirm before you promote.

Changed your mind mid-rotation? Revoke the secondary instead of promoting it. The original key stays primary and nothing is disrupted.

Allowed Origins

Restricts which websites may call the API with your Client key. Leave it empty and any origin is accepted; add entries and everything else is refused. Your project's website URL is offered as a starting point when you first set it.

This is a browser control, not a security boundary.

Origin headers are set by browsers and can be forged by anything that is not one. Allowed Origins stops your key being used from another website; it does not stop someone calling the API directly with curl. Treat it as protection against casual reuse, and rely on the Client key's read-only, published-only scope for everything else.

The kill switch

Deactivating a project stops it serving content immediately. Reach for it when a key has leaked and you need the bleeding to stop before you have time to rotate properly.

What stops

  • Every public API call, Client and Secret alike
  • Your live site's CMS content, wherever it renders
  • Live Preview, including any preview link already shared

What keeps working

  • The dashboard. Editing, saving and publishing are unaffected
  • Your content, untouched and intact
  • Reactivating, which restores service at once

Nothing is deleted and nothing expires while a project is deactivated. It is a switch, not a demolition. The usual sequence is deactivate, rotate, redeploy, reactivate.

Image URLs and drafts

Images are served straight from a CDN, which is what makes delivery fast and egress free. It also means an uploaded file is reachable by anyone holding its URL, and it becomes reachable the moment you upload it. Publishing does not move the file, it starts returning the URL.

Draft images are unlisted, not access-controlled.

The content API never hands out a draft URL without a Secret key or a preview token, so drafts do not leak through the API. But the file itself sits behind an unguessable URL rather than a permission check. Anyone who obtains that URL, from a shared preview session or a screenshot, can fetch the image whether or not it is published.

  • Each version gets its own random path. Knowing one image's URL tells you nothing about any other version of it, published or not.
  • Previous versions stay reachable. Rollback needs them, so their files are kept. Rolling back does not make the newer image unreachable to someone who already has its URL.
  • Deleting an asset deletes its files. Edge caches can serve a deleted image for a while afterwards, until the cached copy expires.

For the content this is built for (site copy, product photos, banners), none of this matters. If you are staging imagery whose existence is confidential before launch, treat an uploaded draft as published and keep it out of the CMS until you are ready.

Preview tokens

A preview token grants draft access for a short window, so a client can see unpublished changes on the real site. Send it as a header:

x-duggie-preview-token: TOKEN

A custom header makes this a cross-origin preflighted request. The public API accepts it from any origin, so the preflight succeeds even with Allowed Origins configured. The origin check runs in the API rather than in CORS, which means a refused origin returns a normal error response you can read, not an opaque browser failure.