SFMC Client Secrets Expire September 30: Rotate Your API Credentials

On September 30, 2026, a meaningful chunk of your Salesforce Marketing Cloud integrations could stop working without warning. Since March 2026, Salesforce has applied a 180-day lifespan to the client secrets behind every Installed Package, and any secret that has not been rotated since March 25, 2026 expires on that date. There is no soft failure and no degraded mode: REST and SOAP calls start returning authentication errors, automations fail, and the pipes feeding your CRM, storefront and warehouse go quiet. Here is how to audit your tenant, cut over without downtime, and turn a looming deadline into a routine you never have to panic about again.

What actually changed

Until this spring, a client secret created inside an Installed Package lived forever. That is how most tenants ended up with five-year-old credentials shared across three vendors and pasted into config files nobody has reviewed since. Salesforce closed that door by giving every secret a hard expiry date.

180 days, no exceptions

Any client secret generated on or after March 25, 2026 expires 180 days later. The rule applies to every Installed Package, Server-to-Server or Web App, on every edition of Marketing Cloud Engagement.

The September 30 cliff

Secrets created before the change get exactly one grace period: they all expire together on September 30, 2026. If you have already rotated a secret since March 25, that package is not on the September clock at all. It expires 180 days from the day you generated the new value. Check the date the platform reports rather than assuming everything lands on the same day.

Where it breaks first

Expiry is binary. The token endpoint stops issuing tokens, and everything downstream fails at once. Map these areas before you touch anything.

AreaWhat you will seeSeverity
REST or SOAP calls from middlewareHTTP 401 on /v2/tokenHigh
SSJS Script activities calling external servicesAutomations erroring outHigh
File imports driven by a third-party platformData Extensions never populatedHigh
CloudPages hitting an internal APIForms failing silentlyMedium
BI and reporting connectorsDashboards frozen on stale dataMedium

Step 1 — Inventory your Installed Packages

Go to Setup > Apps > Installed Packages. The summary table now shows an expiration date for every secret. Export that list, then enrich it with the three things Salesforce will not tell you: who consumes the package, where the secret is stored, and who owns updating it.

This inventory is usually the longest part of the job. In an enterprise tenant it is common to find fifteen to twenty packages, a third of which nobody uses anymore. Take the opportunity to delete the orphans. Every secret you do not have to rotate is an incident you will never have.

To confirm a package is still live, test its client_id and client_secret pair against the token endpoint:

curl -X POST \
  https://YOUR_SUBDOMAIN.auth.marketingcloudapis.com/v2/token \
  -H 'Content-Type: application/json' \
  -d '{
        "grant_type": "client_credentials",
        "client_id": "xxxxxxxxxxxxxxxxxxxxxxxx",
        "client_secret": "yyyyyyyyyyyyyyyyyyyyyyyy",
        "account_id": "7XXXXXXX"
      }'

A 200 response carrying an access_token tells you the package is in use. A 401 means either the secret is already invalid or the package is dormant and can be archived.

Step 2 — Generate and stage the new secret

Open the package and trigger the secret rotation action. Salesforce issues a new value while keeping the previous one alive through a transition window. That overlap is exactly what makes a zero-downtime cutover possible, so use it deliberately instead of letting the old secret lapse on its own.

Put the new secret straight into your vault: AWS Secrets Manager, Azure Key Vault, HashiCorp Vault, or at minimum your CI platform's secret store. Never paste it into a ticket, a chat channel or a shared drive. That handoff is where most credential leaks actually happen.

Step 3 — Cut over without downtime

The underlying best practice is simple: never hardcode a secret. If your integrations read theirs from a vault, the cutover is a single value update. If they do not, handle each consumer individually, in this order: non-production first, then production, starting with the least critical flows.

In code, handle authentication failure explicitly rather than retrying blindly:

import os, requests

def get_token(vault):
    secret = vault.get('sfmc/client_secret')

    resp = requests.post(TOKEN_URL, json={
        'grant_type': 'client_credentials',
        'client_id': os.environ['SFMC_CLIENT_ID'],
        'client_secret': secret,
        'account_id': os.environ['SFMC_MID'],
    }, timeout=10)

    if resp.status_code == 401:
        # Expired or revoked secret: alert once, do not loop.
        notify_ops('SFMC token rejected - check client secret rotation')
        raise RuntimeError('SFMC_AUTH_FAILED')

    resp.raise_for_status()
    body = resp.json()
    return body['access_token'], body['expires_in']

Retrying a 401 only multiplies failed calls and buries the real signal in your logs. A single immediate alert buys you the hours that matter.

Step 4 — Monitor from inside Marketing Cloud

You can also instrument monitoring in Automation Studio itself, with a Script activity that runs weekly. The logic is deliberately dull: attempt an authentication, write the outcome to a supervision Data Extension.

<script runat='server'>
Platform.Load('Core', '1.1.1');
var de = DataExtension.Init('Ops_Auth_Monitor');

try {
  var req = new Script.Util.HttpRequest(tokenUrl);
  req.emptyContentHandling = 0;
  req.retries = 0;
  req.contentType = 'application/json';
  req.method = 'POST';
  req.postData = Stringify({
    grant_type: 'client_credentials',
    client_id: clientId,
    client_secret: clientSecret,
    account_id: mid
  });

  var resp = req.send();

  de.Rows.Add({
    CheckedOn: Now(),
    PackageName: 'Middleware_ETL',
    StatusCode: String(resp.StatusCode)
  });
} catch (e) {
  de.Rows.Add({
    CheckedOn: Now(),
    PackageName: 'Middleware_ETL',
    StatusCode: 'EXCEPTION'
  });
}
</script>

Wire an alert to that Data Extension. The moment a status code other than 200 shows up, you know which package needs attention before production finds out on your behalf.

The mistakes we see most often

The first is the shared secret. When one package serves four integrations, rotation becomes a coordination exercise across four teams and four maintenance windows. The fix is structural: one package per consumer, scoped to exactly what it needs.

The second is forgetting non-production. Sandbox tenants have their own packages with their own expiry dates. They usually break before production does, which is a gift if you are watching them.

The third is confusing secrets with tokens. An access token expires after twenty minutes and refreshes itself. A client secret expires after 180 days and requires a human. If your runbook blurs the two, someone will sit and wait for a refresh that is never coming.

Client secret rotation is not a one-off incident to survive before September 30. It is a twice-yearly ritual that belongs in your operations calendar, right next to TLS certificate renewal.

From fire drill to routine

The teams that will clear this deadline without an incident are the ones that turn the constraint into a habit: a current inventory, secrets centralised in a vault, rotation scheduled thirty days ahead of each expiry, and automated monitoring behind it. It is also a rare excuse to shrink your tenant's attack surface by deleting access nobody remembers granting.

If you would like an audit of your Installed Packages and a rotation plan that fits your architecture, get in touch.

Key takeaways

A hard deadline. Any client secret not rotated since March 25, 2026 expires on September 30, 2026, and authentication fails immediately.

180 days from now on. Every new secret lives 180 days, which makes rotation a twice-yearly ritual rather than an exceptional event.

Inventory before anything else. Map packages, consumers and storage locations before you touch a single credential.

Use a vault, never hardcode. Centralised secrets reduce the cutover to one value update.

Monitor instead of waiting. A weekly authentication check warns you before your users do.

A voir: