Security/Secret Rotation

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

  1. 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).

  2. 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.

  3. 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.

Dashboard — Fetch Agent secret rotation UI with overlap window status
Do not click Deactivate old secret before your edge is updated. Any betterfound requests arriving during that window will fail signature validation and return 401 from your content endpoint.

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-xxxx

Accepting 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'))
  })
}
Store both secrets as separate environment variables (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

PlanDefault overlapMax overlap
Growth1 hour4 hours
Pro12 hours48 hours
Enterprise24 hours7 days