How to verify the preview query parameters of the visual editor?
If the user opens your page in Storyblok, we add a few parameters which you can use to securely validate their use of the edit mode.
You will need that validation to load the right version of your content to the right users. The draft version is for the editor and the published version is for the public.
A simple validation would be to check if there is the _storyblok parameter in url. This could be done in the frontend or in the backend. But for a secure check we recommend to implement the logic in the backend and validate the _storyblok_tk parameter.
Code Examples
Here are some examples of how to securely check if the user is in edit mode:
import crypto from 'crypto'
// getQueryParam = access requests URL param by name
let validationString = getQueryParam('_storyblok_tk[space_id]')
+ ':' + YOUR_PREVIEW_TOKEN
+ ':' + getQueryParam('_storyblok_tk[timestamp]')
let validationToken = crypto.createHash('sha1')
.update(validationString)
.digest('hex')
if (getQueryParam('_storyblok_tk[token]') == validationToken &&
getQueryParam('_storyblok_tk[timestamp]')
> Math.floor(Date.now()/1000)-3600) {
// you're in edit mode.
this.editMode = true
} Zero-downtime Preview Token Rotation
The _storyblok_tk[token] signature is generated with one specific preview token from your space. If your space has more than one preview token, which one gets used is not configurable. Validating against a single hardcoded token will break as soon as that changes.
Accept a list of preview tokens instead of one:
import crypto from 'crypto'
// Every preview token that should be accepted, e.g.
// process.env.STORYBLOK_PREVIEW_TOKENS.split(',')
const PREVIEW_TOKENS = [YOUR_PREVIEW_TOKEN, YOUR_NEW_PREVIEW_TOKEN]
// getQueryParam = access requests URL param by name
let spaceId = getQueryParam('_storyblok_tk[space_id]')
let timestamp = getQueryParam('_storyblok_tk[timestamp]')
let signature = Buffer.from(getQueryParam('_storyblok_tk[token]'), 'hex')
let matches = PREVIEW_TOKENS.filter((previewToken) => {
let validationToken = crypto.createHash('sha1')
.update(spaceId + ':' + previewToken + ':' + timestamp)
.digest()
return validationToken.length === signature.length &&
crypto.timingSafeEqual(validationToken, signature)
})
if (matches.length > 0 && timestamp > Math.floor(Date.now()/1000)-3600) {
// you're in edit mode.
this.editMode = true
} To rotate without downtime:
- Create the new preview token in Storyblok. The editor keeps signing with the previous one, so nothing breaks yet.
- Add the new token to
PREVIEW_TOKENSand deploy. Both old and new are now accepted. - Delete the old preview token in Storyblok. Deleting it is what makes the editor switch.
- Optionally remove the old token from
PREVIEW_TOKENSon your next deploy.