Reading time: 11 min read

Tips to regenerate SitecoreAI Context IDs and API Tokens successfully

Procedures, incident response, and maintenance

Portrait photo of David Austin, article author

Rotation and incident response for vulnerable Sitecore Context IDs & API tokens

Ensuring your site or your clients' site security is up-to-date and secure is always of utmost importance. If Sitecore XM Cloud (SitecoreAI / Sitecore Cloud Portal) Context IDs and API Tokens even potentially have been exposed, for example, through a leaked hosting provider environment like Vercel, an accidentally committed .env file, a screenshot in a ticket, or a former contributor retaining access, you need to react promptly, efficiently, and correctly. Failing to do so can be destructive.

First we will cover the steps to resolve the issues and then we will cover what you can do to prevent issues like this in the future and how you should react.

What you are protecting

Context IDs

A Context ID identifies a specific Sitecore XM Cloud environment context. It's the binding between an environment, a site, and a delivery surface and is used by a headless app to fetch layout, content, dictionary, and personalization data from Sitecore Edge.

Typical environment variables (names vary slightly by template version, you can see the SitecoreAI Context ID env-var reference for the authoritative list) that may need to be listed as sensitive include the following:

  • SITECORE_EDGE_CONTEXT_ID - server-side, production / live edge
  • NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID - client-exposed counterpart (Next.js bundles NEXT_PUBLIC_* into the browser JS at build time)
  • A separate preview Context ID variant for editing / preview surfaces
  • (Legacy) SITECORE_API_KEY - older XM Cloud projects or those that haven't switched to Context ID usage

A Context ID is not a username/password. Think of it more as a tenant identifier. On its own, it does not grant write access. However, an attacker holding a live Context ID can:

  • Scrape the full content tree, including unpublished items if preview is misconfigured
  • Enumerate routes, components, and personalization variants
  • Drive up Edge request quota and billing
  • Mirror the site for phishing

Treat Context IDs as moderately sensitive. Public app code paths leak them anyway (the browser eventually sees the live one), but the preview Context ID and any non-production Context IDs should be guarded.

API tokens

API Tokens are the high-impact secret. In a typical Sitecore XM Cloud + headless stack you will see the following, each having different levels of access:

  • XM Cloud Deploy / Sitecore Cloud Portal API token: can deploy, restart, read logs, modify environment variables. Treat as production credentials.
  • JSS Editing Secret / Sitecore Editing Secret (JSS_EDITING_SECRET / SITECORE_EDITING_SECRET): shared secret between the XM Cloud editing host and the headless preview deployment. An attacker with this can submit forged editing requests against the editing host.
  • GraphQL / Authoring API tokens: read or write access to the content authoring API.
  • Sitecore Search / Discover / CDP / Personalize API keys: depending on which products are wired in.
  • Client ID / Client Secret: enables authorization access and subsequently read or write access to various levels.

Treat any API Token as highly sensitive. Exposure = rotate now.

How to revoke, rotate and regenerate credentials

Revoking and rotating an API token

API Tokens for an SitecoreAI project are surfaced in the Deploy UI > Details tab for the relevant project / environment.

API Token in Deploy UI

Revocation itself is performed through the Sitecore Token API. Using the Token API is what guarantees the token is invalidated server-side and can no longer be presented as a valid credential. See the endpoint reference: https://doc.sitecore.com/sai/en/developers/sitecoreai/experience-edge/experience-edge-apis/token-rest-api.html

I recommend revoking the old API Token first as in order to regenerate a Context ID it requires a an active Deploy API Token. It was discovered if you revoked a token and then tried to regenerate a Context ID this would fail. This issue has since been resolved, but it is why I recommend doing the API Token first to avoid issues in regeneration of the Context IDs.

IMPORTANT: If you were using an API Token, i.e. the Delivery API Token found on the Details tab of a project's environment. Revoking it will IMMEDIATELY create failures in all environments that use it.

Procedure:

  1. Find the original API Token via Deploy UI > Details tab in the SitecoreAI Deploy site.
  2. At the bottom you will be able to click Generate Delivery API Token. This doesn't actually generate one if an unrevoked token is available. It will merely show you the active one. So before you can get the new API token first revoke the one shown.
  3. Revoke the old token via the Token API:
    1. Obtain Client ID and Client Secret values for the appropriate environment in the Credentials page of the SitecoreAI Deploy site.

      Credentials page in SitecoreAI Deploy

    2. Use those credentials to obtain a JWT token from the auth endpoint: https://auth.sitecorecloud.io/oauth/token. Find details on how to get an auth token here: https://doc.sitecore.com/cdp/en/developers/api/request-an-access-token.html
    3. Then using the token you grabbed from the Generate Delivery API Token button, perform a revoke token call to: https://edge.sitecorecloud.io/api/apikey/v1/revokebytoken. You can find details of the parameters required here: https://doc.sitecore.com/sai/en/developers/sitecoreai/experience-edge/experience-edge-apis/token-rest-api.html#revokebytoken
    4. You will receive a 200 when success.
  4. Go back to Details tab in the Deploy UI and click Generate Delivery API Token and you will get your new API Token. Your old one is IMMEDIATELY unusable.
  5. If you maintain operational scripts, keep a revoke-token.sh (or equivalent) that wraps the API call and can be run during an incident without anyone having to look up curl syntax under pressure. This requires a multi-stage script, but could be handy for anyone to have.
  6. Confirm revocation by attempting to use the old token against any read-only endpoint or Edge Playground. You will know if it works if it must return 401/403.

A good rule of thumb is any token that has been exposed or potentially exposed, not just confirmed-leaked, must go through this revoke flow. "We're not sure if it leaked" is a revoke condition, not a wait-and-see condition.

Regenerating the editing secret

The editing secret is set in two places and both must change together:

  • The XM Cloud editing host configuration (Sitecore side)
  • The hosting provider env var JSS_EDITING_SECRET or SITECORE_EDITING_SECRET consumed by the editing route handler in the headless app

Mismatch will break editing in Sitecore Pages. Coordinate with whoever owns the Sitecore environment, set both, then redeploy.

In order to regenerate it, you need to use the Deploy API, similar to how you did the API Token above. Let's follow the steps:

  1. Obtain Client ID and Client Secret values for the appropriate environment in the Credentials page of the SitecoreAI Deploy site.
  2. Use those credentials to obtain a JWT token from the auth endpoint: https://auth.sitecorecloud.io/oauth/token. Find details on how to get an auth token here: https://doc.sitecore.com/cdp/en/developers/api/request-an-access-token.html
  3. Then you'll hit the regenerate-editing-secret endpoint using the JWT and the environmentId found on the Deploy UI > Details page. You can find the POST command here: https://xmclouddeploy-api.sitecorecloud.io/swagger/index.html#/Environments/RegenerateEditingSecretKey It involves performing a POST command to: https://xmclouddeploy-api.sitecorecloud.io/api/environments/v1/{environmentId}/regenerate-editing-secret
  4. You will then need to redeploy all environments that utilize it.

Rotating a Context ID

Context IDs are issued per environment and come in two variants. You can find them in the Deploy interface.

Context IDs in the Deploy interface

  1. Revoke the old Context ID in the portal once the new one is verified live. Do not skip this step as it is the entire point of the rotation.
  2. Sitecore Cloud Portal > SitecoreAI Deploy > Select the project > Select the environment
  3. Select the Details tab
  4. Click Regenerate next to the original Context IDs. The portal issues a new ID; the old one remains valid for a grace window but will be fully deactivated upon redeployment of the back-end environment from within Sitecore. You have about 30 minutes before it is fully gone.
  5. Update the corresponding env var in the hosting provider for all environments where it is used (Production, Preview, Development, plus any CI runners).
  6. Trigger a redeploy of every environment that consumes the variable. A new build is usually required as most hosting providers do not hot-reload env vars into already-deployed functions. As is the case with Vercel. You have to redeploy it.
  7. Verify the new ID is in use: open the deployed site, check a network request to the Edge endpoint, confirm the new Context ID is on the request.

Local developer machines

After rotation, every developer needs to update local .env.local (and per-environment files such as .env.qa, .env.staging). Communicate the rotation through a secret manager, but please, do not paste the new value in chat.

Improving SitecoreAI security

There are always things you can do to improve security around Context IDs, API Tokens, etc. Scoping Context IDs are but one way when you need to use them in precarious locations.

Use scoped Context IDs for client-exposed env vars

Any env var with a public-build prefix is bundled into the browser JavaScript at build time and is therefore visible to anyone who opens DevTools. The most common offender is NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID. Any variable starting with NEXT_PUBLIC_* is always available in the front-end client bundles and in older versions of SitecoreAI, people needed to use the Context ID for NEXT_PUBLIC_ to ensure analytics worked. This has since been rectified to allow you to use multiple Context IDs for various purposes.

These are not "leaked", they are public by design. The mitigation is not to hide the value but to limit what it can do. Sitecore Cloud Portal supports this by letting you create a scoped Context ID. What that is, is a Context ID that is restricted to a specific allow-list of origins (and optionally other constraints), so that even when the value is read out of the client bundle by a third party, it cannot be used from unauthorized domains.

Rule: the un-scoped (default) Context ID should never be the value placed in a NEXT_PUBLIC_* (or other client-exposed) variable. Use a scoped Context ID for every surface where the value will reach the browser.

Recommended pattern after a rotation:

  1. Regenerate the Context ID as part of the rotation procedure above.
  2. Also create a scoped Context ID restricted to the production hostname(s) and a separate scoped ID per non-production hostname (preview deployments, staging, QA). Do not reuse one scoped ID across environments; the scope list should be tight and ultimately you should have one analytics Context ID per site for it to work properly.
  3. Place the scoped ID in any client-exposed variable (NEXT_PUBLIC_SITECORE_EDGE_CONTEXT_ID, etc.).
  4. Reserve the un-scoped ID strictly for server-only variables (no public prefix), if it is needed at all.
  5. If the client-exposed ID is observed being abused (request spikes, scraping, traffic from unexpected origins), tightening the scope list is faster than a full rotation and does not require a redeploy of the app.

For the click-through steps to create a scoped Context ID, see the official Sitecore documentation: https://doc.sitecore.com/portal/en/developers/sitecore-cloud-portal/manage-context-ids.html#create-a-scoped-context-id

The portal UI changes from time to time so always cross-reference the live documentation rather than relying on a screenshot in an internal wiki.

Incident response

A typical exposure: a hosting provider project was set to public, a preview link was shared too widely, env vars were viewable to a wider audience than intended, or a .env file was committed.

The example below uses Vercel terminology, but the same playbook applies to Netlify, Azure App Service, AWS Amplify, Cloudflare Pages, or any other host that stores environment variables.

When to rotate your Context IDs and API tokens

ScenarioContext IDAPI Token
Committed to git history (any branch, any time)RotateRotate immediately
Pasted in Slack/Teams/email/ticketConsider rotatingRotate
Visible in a screenshot shared externallyConsider rotatingRotate
Hosting provider env vars exposed (e.g. public Vercel project, leaked Netlify dashboard, misconfigured Azure App Service)RotateRotate immediately
Contractor or employee with access has leftOptionalRotate
Unknown — "I think it might have leaked"RotateRotate
Routine hygieneAnnuallyEvery 90 days, or per policy

Rule of thumb: if you are debating whether to rotate an API token, rotate it. The cost of rotation is one deploy, potentially a short outage. The cost of a missed rotation is unbounded.

How promptly should you rotate IDs and tokens

Time-to-rotate budgets, from the moment exposure is suspected:

  • Client ID / Client Secret: immediately.
  • API Tokens with write/deploy scope: within 1 hour. These can be used to push code, change env vars, or exfiltrate authoring data.
  • JSS Editing Secret: within 4 hours. Lower blast radius but still a forgery vector.
  • Production Context ID: within 24 hours. Plan a deploy window.
  • Non-production Context IDs: within 1 week.

Steps to follow in first 15 minutes

  1. Lock down access. Project settings → Members. Remove anyone who should not be there. Switch the project to private.
  2. Inventory what was visible. Project settings → Environment Variables. List every variable name. Assume every value was read.
  3. Open a temporary incident channel. Pin the incident commander. All rotation activity gets logged here.

Steps to follow in first hour

  1. Rotate every API Token in the inventory (see procedure above). Highest scope first: deploy tokens, then editing secret, then read-only tokens.
  2. Rotate any third-party secrets that were also in the env: analytics keys, CDP API keys, payment provider keys, captcha secrets, error-reporting DSNs. The hosting provider does not differentiate if they were in the project, treat them as exposed.
  3. Disable any deploy hooks the project had configured and reissue them.

Steps to follow in first day

  1. Rotate Context IDs for the affected environments.
  2. Audit Sitecore Cloud Portal logs for the past 30 days: unusual deploys, env var changes, login locations, content publishes.
  3. Audit hosting-provider deployment logs: unexpected deployments, function invocations from unusual IPs, anomalous bandwidth.
  4. If billing anomalies appear (Edge request spikes, function execution spikes), escalate to Sitecore support with the audit window.

Steps to follow in first week

  1. Post-mortem. Document how the exposure happened, not who. The fix is almost always procedural (project visibility defaults, secret-scanning in CI, onboarding/offboarding checklist).
  2. Add the leaked secret patterns to CI secret-scanning rules (GitGuardian, GitHub secret scanning, gitleaks, TruffleHog) so the same shape never enters git again.
  3. If a customer-facing surface was impacted (forged content, scraped data), loop in legal/comms per the organization's disclosure policy.

Maintenance checklist

Run this quarterly:

  • No .env* files in git history (git log --all --full-history -- "*.env*")
  • All secrets in the hosting provider are present in the secret manager (1Password, Azure Key Vault, AWS Secrets Manager, HashiCorp Vault, etc.) under the same name
  • No API tokens older than 90 days unless documented as long-lived service accounts
  • No Context IDs older than 12 months
  • Hosting-provider project member list reviewed; ex-contractors removed
  • Sitecore Cloud Portal user list reviewed
  • Secret-scanning enabled on the repo
  • This document's rotation procedures still match the current portal UI. Always good to revalidate the procedures as the interface and process can and has changed.

References