I write posts in barakoCMS the same way you'd expect: draft it, read it back, decide it's not embarrassing, then hit publish. The problem is the middle step. The CMS's public API only ever returns published content. That's not an oversight. That's the whole point of the delivery API — anonymous readers should never see a draft, a half-written page, or a typo I haven't caught yet.
So how do you preview something nobody else can see?
The obvious wrong answer is to expose drafts through the public API and filter them out later, or fake it with a cookie. Both of those turn "preview" into a second, quieter way to leak content that's supposed to be private.
What I built instead is a token scoped to exactly one entry. When I'm logged into the admin looking at a draft, I can ask for a preview link for it. The server checks that I actually have read access to that content type first, the same check the real editor screen uses, then mints a short-lived JWT bound to four things: this tenant, this content type, this slug, and this entry's id. Thirty minutes, then it's dead.
That token rides in the URL: /blog/my-new-post/?preview=eyJhbGc.... Anyone with the
link can open it and see the draft rendered exactly like a published post. Nobody
else can. The token can't be repurposed either way — it carries its own JWT
audience, separate from the one real API credentials use, so even if it ended up in
a server log somewhere it wouldn't work as a login.
Two details I was careful about, because they're the kind of thing that goes wrong quietly:
- The preview token doesn't turn off field-level sensitivity. If a field on that content type is marked Sensitive, it stays stripped out of the response even in preview mode. A preview link is for seeing your own draft, not a way to see everything else the CMS normally hides.
- Asking for a preview link on a slug that doesn't exist, and asking for one you're not allowed to see, return the exact same 404. If they didn't, the endpoint itself would become a way to fingerprint which draft slugs exist just by trying names against it.
None of this is visible anywhere on the site right now, which is a little on the
nose given the subject. It shipped in 3.11.0. If you're running your own barakoCMS
instance, it's already there: POST /api/preview with a type and a slug, and you
get back a token and an expiry.