Secret Rotation
Rotate your fetch agent secret at any time without downtime. betterfound supports a dual-secret overlap window so your edge can accept both old and new secrets during the cutover.
When to rotate
- A team member with access to the secret leaves the organisation
- You suspect the secret has been compromised
- Your security policy mandates periodic rotation (recommended every 90 days)
- You are migrating your edge infrastructure to a new secrets manager
Zero-downtime rotation procedure
In the betterfound dashboard, go to Settings → Fetch Agent → Rotate secret. betterfound generates a new secret and begins signing requests with it immediately. The old secret remains valid during the overlap window (default 24 hours).
Update your edge configuration (WAF custom rule, content endpoint environment variable, or secrets manager) with the new secret. Verify with the smoke test curl command.
Once your edge is accepting requests signed with the new secret, return to the dashboard and click Deactivate old secret. betterfound will stop accepting the old signature immediately.
API-driven rotation
You can also rotate via the management API:
# Step 1: Generate new secret (old remains valid)
POST https://api.betterfound.ai/v1/tenants/fetch-agent/rotate
Authorization: Bearer sk-sm-xxxx
# Response
{
"new_secret": "aabbcc...new...",
"old_expires_at": "2026-05-25T10:00:00Z"
}
# Step 2: Update your edge, then deactivate old secret
POST https://api.betterfound.ai/v1/tenants/fetch-agent/deactivate-old
Authorization: Bearer sk-sm-xxxxAccepting both secrets during overlap
If you manage your own content endpoint (Tier B), update your verification function to accept either secret during the cutover window:
import { createHmac, timingSafeEqual } from 'node:crypto'
const SECRETS = [
process.env.BETTERFOUND_SECRET_NEW, // try new first
process.env.BETTERFOUND_SECRET_OLD, // fallback to old during overlap
].filter(Boolean)
function verifyWithAnySecret(req, originalUrl) {
const tenantId = req.headers['x-shopmind-tenant']
const timestamp = Number(req.headers['x-shopmind-timestamp'])
const provided = String(req.headers['x-shopmind-signature'] ?? '')
if (!tenantId || !Number.isFinite(timestamp)) return false
if (Math.abs(Date.now() - timestamp) > 5 * 60 * 1000) return false
return SECRETS.some(secret => {
const expected = createHmac('sha256', secret)
.update(`${tenantId}\n${timestamp}\n${originalUrl}`)
.digest('hex')
return provided.length === expected.length &&
timingSafeEqual(Buffer.from(expected, 'hex'), Buffer.from(provided, 'hex'))
})
}BETTERFOUND_SECRET_NEW and BETTERFOUND_SECRET_OLD) in your secrets manager. Once you deactivate the old secret in the dashboard, remove BETTERFOUND_SECRET_OLD from your environment.Overlap window duration
| Plan | Default overlap | Max overlap |
|---|---|---|
| Growth | 1 hour | 4 hours |
| Pro | 12 hours | 48 hours |
| Enterprise | 24 hours | 7 days |