← All articles

Slack token expiration: what breaks, when, and how to plan

Key takeaways

  • Modern Slack bot and user tokens are short-lived and paired with a refresh token, while legacy tokens can keep working for years.
  • An expired Slack token fails with HTTP 401 and invalid_auth, and scheduled messages or workflows fail silently with no warning pushed by Slack.
  • Stripe API keys never expire on a clock; rotation is a manual decision using dual keys and an overlap window.
  • Vault exposes token TTLs via vault token lookup and lease lookup, but renewal stops at the mount's max_lease_ttl.
  • Vaults like Secrets Manager and Infisical track stored secrets, not SaaS-side expiry, so Slack and Stripe credentials outside the vault age invisibly.

Slack token expiration means most tokens your integrations rely on now stop working after a fixed window unless your app refreshes them, and Slack is deliberately moving away from long-lived tokens. This walkthrough covers how Slack's expiry mechanics work, what breaks when a token lapses, and how the model compares to Stripe and Vault, so you can map owners and rotation deadlines before users report the outage.

How does Slack token expiration work?

Slack issues several token types, and they do not all behave the same way on expiry. Bot tokens (xoxb) and user tokens (xoxp) created through modern apps are short-lived and come paired with a refresh token (xoxr). App-level tokens (xoxa) and legacy tokens behave differently, and older workspace-token installations can keep working for years unless you intervene.

Slack has been moving away from long-lived tokens deliberately. New apps that use token rotation exchange a short-lived access token plus a refresh token, so every credential carries an explicit expiry instead of an indefinite lifetime. Legacy tokens still exist in older installs, which is exactly where credential sprawl starts: nobody knows which of the three models a given integration uses until it breaks.

Where does the expiry metadata actually live? Two places. The token response from oauth.v2.access returns an expires_in field alongside the refresh token, so your install code sees the deadline at issuance. After that, auth.teams.list (and auth.test for the calling token) validates a token on demand and returns the teams it is active for, which is how you detect a token that has quietly stopped working. Neither endpoint pushes a warning before expiry; you have to poll or track the deadline yourself, the same problem you face tracking 30/60/90 day rotation policies for AWS and Stripe keys (credential expiration reminder tools).

What happens when a Slack token expires?

An expired Slack token fails with an HTTP 401 and a invalid_auth error in the response body. Any API call your integration makes returns that error until someone issues a new token and updates every place the old one is stored.

HTTP 401 invalid_auth vs token_refresh_failed

invalid_auth means the token is dead: revoked, expired, or wrong. There is no refresh path in Slack's model for these tokens; you re-authorize the app or mint a new token. token_refresh_failed is different: it appears when a refresh token exchange fails, often because the refresh token was rotated or revoked out from under the app. The first demands re-issue, the second demands debugging the refresh flow.

Silent failures in workflows and scheduled messages

Scheduled messages and workflow steps fail without a human watching the response. The message just never posts, and the first signal is a missing notification hours later. An explicit API key expiration policy with named owners turns that silence into a deadline someone owns.

How does Stripe token expiration differ from Slack's?

Stripe API keys do not expire on a clock. Slack's platform tokens do, and the failure mode differs accordingly: a Slack call with a dead token returns invalid_auth or token_refresh_failed in the Slack API error documentation, while a Stripe call with a revoked key fails with an authentication error only when someone revokes it.

Stripe key types: secret keys, restricted keys, publishable keys

Key typeExpires on its own?Typical blast radius
Secret key (sk_live_…)NoEverything server-side
Restricted key (rk_live_…)NoScoped permissions only
Publishable key (pk_live_…)NoClient-side, low risk

Stripe's rotation model: dual keys and overlap windows

Stripe's rotation works through overlap: you roll a secret key to a new value, keep both live during a cutover window, then revoke the old one. Expiry is a decision you make, not a deadline Stripe enforces. That is the inverse of Slack, where OAuth refresh tokens lapse on Slack's schedule whether you planned for it or not.

The operational gap is the same either way: nobody wrote down who owns the key or when the overlap window ends. We track that metadata layer separately, without holding the secret value itself — see how to track API key expiry across providers.

How do you check token expiration in Vault?

Vault exposes token TTLs through its CLI and API, so you can inspect expiry without reading the secret value itself.

vault token lookup and lease lookup commands

Run vault token lookup with a token to see its ttl, creation_ttl, renewable flag, and issue_time. The API equivalent is GET /v1/auth/token/lookup-self, which returns the same metadata. For dynamic secrets, vault lease lookup <lease_id> shows the lease TTL and whether it is renewable. If you want inventory rather than a single token, vault list auth/token/accessors enumerates accessors you can then look up one by one, which is how most teams find orphaned tokens nobody claims.

Renewal vs reissue: renewable leases and max_ttl

A renewable token can be extended with vault token renew, but only up to the mount's max_lease_ttl; past that, Vault forces a reissue. That distinction matters for your rotation policy: renewal keeps a credential alive, reissue creates a new one and retires the old. Track creation_ttl against max_ttl per token so you know which ones will hit a hard stop instead of quietly renewing.

For a worked checklist across Slack, Stripe, and Vault, see the integration credentials brief.

Why do Slack integrations break after token rotation?

Rotation usually fails not because the new token is invalid, but because something is still holding the old one.

Cached tokens in CI, Postman collections, and serverless env vars

A rotated Slack token in Secrets Manager does nothing for the copy baked into a GitHub Actions secret, a Lambda environment variable, or a developer's Postman collection. Those copies keep failing until someone updates each one by hand. This is the "humans are the transport layer" problem: the vault is fine, the distribution is not. Stripe's own guidance on key rotation acknowledges the same gap, noting that rolling API keys requires updating every place a key is deployed (Stripe API documentation). We covered manual rotation tracking patterns in more depth at alternatives to manual credential rotation tracking.

Refresh token flow mistakes and clock skew

Slack's refresh token flow adds a second failure mode: an integration that caches the refresh token but never rotates the access token, or one whose clock drifts past the expiry window, gets rejected even though credentials are technically current. Both look identical to a broken token from the user's side.

How should teams prepare for expiring Slack tokens?

Assign an owner and rotation deadline per token

Every Slack token gets a named owner ("Payments platform", "Platform engineering") and a rotation deadline in your tracking layer, whether that is a spreadsheet or a vault. Slack's app tokens carry no visible expiry in Secrets Manager, so the deadline has to come from you. A 30/60/90 day policy applied per token beats a vague "rotate regularly" rule nobody owns.

Prefer refresh-token flows over manual reissue

Where Slack offers refresh tokens, use them so the app renews its access without a human copying a new secret into Postman or a config file. Humans are the transport layer, and every manual reissue is a chance for sprawl. For anything still long-lived, document the reissue steps before the expiry, not during the outage.

Stage rotation with overlap windows

Rotate on a schedule with an overlap window: issue the new token, confirm the integration works, then revoke the old one. Test against a staging workspace first, and page the token owner, not the whole team, if the cutover fails.

What monitoring catches expired tokens before users notice?

Two layers catch expiry-driven breakage: monitoring the credential's metadata, and monitoring the integration's behavior. Most teams have neither, because the vault they already pay for only watches the first half of the problem.

Metadata-only monitoring vs secret custody

Metadata-only monitoring tracks owner, expiry date, and rotation deadline without ever reading the secret value. That separation matters: your monitoring layer cannot leak what it never stores. Stripe's own docs push this direction, since restricted keys let you scope a credential to specific resources instead of handing a full-access secret to every integration. The trade-off is honesty about coverage: metadata-only monitoring cannot tell you a dev pasted a key into a Postman collection. It only tells you the credentials you registered are aging on schedule.

Where vaults stop: AWS Secrets Manager, Vault, and Infisical track storage, not SaaS expiry

Secrets Manager, HashiCorp Vault, and Infisical all record what they store and can enforce rotation for credentials that live inside them. None of them know that a Slack token expires server-side or that a Stripe key was revoked in the vendor's dashboard. If the credential never entered the vault, its expiry is invisible to the vault. That gap is where users notice first, and where a lifecycle layer that ingests expiry metadata from the provider, not just from storage, earns its keep.

Which tool fits your team's token lifecycle gap?

Where each tool stops short

Doppler, HashiCorp Vault, and Infisical all hold secret values and can rotate some of them. None of them is designed to answer the question your Reddit thread keeps circling: who owns this key, when does it expire, and what breaks on day 90? Vault tracks leases for the secrets it issues, but your Slack and Stripe tokens usually live outside that model. Doppler and Infisical centralize storage, not lifecycle ownership across SaaS providers. The gap is coordination: an audit trail of expiry dates and rotation deadlines for credentials your vault never sees.

Where KeyGuardRail falls short too

KeyGuardRail monitors metadata only. It never holds a secret value, so it cannot rotate anything for you. If you want a vault, keep the one you have. What it adds is expiry visibility and ownership mapping across AWS, Stripe, and GitHub, so a Slack token expiration surfaces on a dashboard instead of in a broken integration. If your problem is transport, not tracking, it is the wrong tool.

FAQ

Do Slack bot tokens ever expire, or only user tokens?

Both can. Modern bot tokens (xoxb) and user tokens (xoxp) issued through apps with token rotation are short-lived and paired with a refresh token (xoxr). Legacy tokens and older workspace installs may keep working indefinitely unless you intervene. Which model a given integration uses is often unknown until something breaks, so audit each token's type first.

How do I get notified before a token expires instead of after an outage?

Slack pushes no warning before expiry, so you have to track the deadline yourself. The oauth.v2.access response returns expires_in at issuance; poll auth.teams.list or auth.test to validate tokens on demand. Record an owner and rotation deadline per token, and set reminders against that metadata rather than waiting for a 401.

How does Slack token expiration differ from Stripe's key model?

Slack's platform tokens expire on Slack's schedule whether you planned for it or not, failing with invalid_auth or token_refresh_failed. Stripe API keys do not expire on a clock; a call only fails when someone revokes the key. Stripe rotation relies on dual keys and an overlap window you control, so the deadline is your decision, not the vendor's.