Slack API Error Guide: 'token_revoked' and 'token_expired' Dead Credentials
Fix the Slack API token_revoked and token_expired errors: diagnose uninstalled apps, admin revocation, rotated tokens, and expiring OAuth tokens with curl.
- #slack
- #troubleshooting
- #errors
- #authentication
Overview
The token_revoked and token_expired errors mean a token that was once valid is no longer usable. token_revoked is permanent — the app was uninstalled, an admin killed the credential, or it was explicitly revoked via auth.revoke. token_expired applies to apps using token rotation, where access tokens are short-lived and must be refreshed with the refresh token before they lapse. Both differ from invalid_auth (a malformed/never-valid token): here the token was good and then stopped being good.
You will see one of these in the JSON body:
{
"ok": false,
"error": "token_revoked"
}
{
"ok": false,
"error": "token_expired"
}
It occurs at the authentication layer of any Web API call, so auth.test reproduces it immediately.
Symptoms
- Every call returns
token_revokedortoken_expired, not just one endpoint. - The token worked previously, then stopped abruptly (revoked) or on a schedule (expired).
- An admin uninstalled/reinstalled the app, or rotated credentials.
- For rotation-enabled apps, the access token has aged past its lifetime.
curl -s "https://slack.com/api/auth.test" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN"
{
"ok": false,
"error": "token_revoked"
}
Common Root Causes
1. The app was uninstalled from the workspace
Uninstalling revokes all of that install’s tokens permanently. Cached tokens in CI keep failing with token_revoked.
curl -s "https://slack.com/api/auth.test" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN"
{
"ok": false,
"error": "token_revoked"
}
Reinstall the app and pull the freshly issued token.
2. An admin or owner revoked the token
A workspace admin can revoke a specific token from the admin console or via the API, often during a security review.
# Anyone can explicitly revoke a token they hold:
curl -s "https://slack.com/api/auth.revoke" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN"
{
"ok": true,
"revoked": true
}
After this, every subsequent call with that token returns token_revoked.
3. Token rotation is enabled and the access token expired
Apps with token rotation receive short-lived access tokens (xoxe.xoxp-/xoxe-) plus a refresh token. Once the access token’s lifetime elapses, calls return token_expired.
curl -s "https://slack.com/api/auth.test" \
-H "Authorization: Bearer $SLACK_ACCESS_TOKEN"
{
"ok": false,
"error": "token_expired"
}
You must exchange the refresh token for a new access token.
4. The refresh token was not used in time / is itself invalid
If your service never refreshed, or the refresh token was rotated out from under it, refreshing fails too.
curl -s -X POST "https://slack.com/api/oauth.v2.access" \
-d "client_id=$SLACK_CLIENT_ID" \
-d "client_secret=$SLACK_CLIENT_SECRET" \
-d "grant_type=refresh_token" \
-d "refresh_token=$SLACK_REFRESH_TOKEN"
{
"ok": false,
"error": "invalid_refresh_token"
}
A bad refresh token means you must re-run the OAuth install flow.
5. The app was reinstalled, minting new tokens
Reinstalling issues new tokens and revokes the prior set. Services holding the old value see token_revoked.
curl -s "https://slack.com/api/auth.test" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN"
{
"ok": false,
"error": "token_revoked"
}
6. A leaked token auto-revoked by Slack
Slack scans public repos and revokes tokens it detects as leaked, returning token_revoked thereafter.
curl -s "https://slack.com/api/auth.test" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN"
{
"ok": false,
"error": "token_revoked"
}
Rotate the credential and purge it from history if this happens.
Diagnostic Workflow
Step 1: Confirm the exact error with auth.test
curl -s "https://slack.com/api/auth.test" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN"
token_revoked (permanent) and token_expired (refreshable) have different fixes, so read the exact string.
Step 2: For token_expired, refresh the access token
curl -s -X POST "https://slack.com/api/oauth.v2.access" \
-d "client_id=$SLACK_CLIENT_ID" \
-d "client_secret=$SLACK_CLIENT_SECRET" \
-d "grant_type=refresh_token" \
-d "refresh_token=$SLACK_REFRESH_TOKEN"
{
"ok": true,
"access_token": "xoxe.xoxb-...new...",
"refresh_token": "xoxe-1-...rotated...",
"expires_in": 43200
}
Store the new access_token AND the rotated refresh_token.
Step 3: For token_revoked, determine why
Check whether the app is still installed (OAuth & Permissions page shows an active install) and whether an admin revoked it. A revoked token cannot be refreshed — it must be replaced.
Step 4: Reinstall or re-run OAuth to mint a new token
For a revoked bot token, reinstall the app and copy the new Bot User OAuth Token. For a rotation app with a dead refresh token, re-run the full OAuth install flow.
Step 5: Update the secret store and verify
curl -s "https://slack.com/api/auth.test" \
-H "Authorization: Bearer $SLACK_BOT_TOKEN"
{
"ok": true,
"team": "ACME Prod",
"user_id": "U0BOTBOT01"
}
Example Root Cause Analysis
A long-running integration that uses token rotation starts returning token_expired every twelve hours, recovering only after a manual redeploy.
curl -s "https://slack.com/api/auth.test" -H "Authorization: Bearer $SLACK_ACCESS_TOKEN"
{"ok": false, "error": "token_expired"}
Inspecting the refresh code, the service exchanges the refresh token but only persists the new access_token — it discards the rotated refresh_token Slack returns each time:
{"ok": true, "access_token": "xoxe.xoxb-...", "refresh_token": "xoxe-1-...rotated...", "expires_in": 43200}
Because Slack rotates the refresh token on every exchange, reusing the original one eventually fails, and the access token then expires with no way to refresh.
Fix: persist BOTH returned tokens on every refresh, and refresh proactively before expires_in elapses:
curl -s -X POST "https://slack.com/api/oauth.v2.access" \
-d "client_id=$SLACK_CLIENT_ID" -d "client_secret=$SLACK_CLIENT_SECRET" \
-d "grant_type=refresh_token" -d "refresh_token=$SLACK_REFRESH_TOKEN"
Storing the rotated refresh token each cycle keeps the integration alive indefinitely.
Prevention Best Practices
- Distinguish the two errors in code:
token_expiredtriggers an automatic refresh;token_revokedpages a human to reinstall. - For rotation apps, always persist the rotated
refresh_tokenreturned on every exchange — reusing the old one is the classic failure. - Refresh access tokens proactively, well before
expires_in, rather than waiting for the firsttoken_expired. - Run
auth.testas a health check so a revoked token surfaces at boot, not during an incident. - Never commit tokens to repos; Slack auto-revokes leaked credentials, and prevention beats rotation under fire.
- For ad-hoc triage, the free incident assistant can tell an expired (refreshable) token apart from a revoked (replace-only) one. See more in Slack guides.
Quick Command Reference
# Which failure is it?
curl -s "https://slack.com/api/auth.test" -H "Authorization: Bearer $SLACK_BOT_TOKEN"
# Refresh an expired access token (rotation apps)
curl -s -X POST "https://slack.com/api/oauth.v2.access" \
-d "client_id=$SLACK_CLIENT_ID" -d "client_secret=$SLACK_CLIENT_SECRET" \
-d "grant_type=refresh_token" -d "refresh_token=$SLACK_REFRESH_TOKEN"
# Explicitly revoke a token you hold
curl -s "https://slack.com/api/auth.revoke" -H "Authorization: Bearer $SLACK_BOT_TOKEN"
# Verify a replacement token
curl -s "https://slack.com/api/auth.test" -H "Authorization: Bearer $SLACK_BOT_TOKEN"
Conclusion
token_revoked and token_expired both mean a previously valid token has died — the difference is whether it can be revived. The usual root causes:
- The app was uninstalled, permanently revoking its tokens.
- An admin or owner explicitly revoked the credential.
- Token rotation is on and the short-lived access token expired.
- The refresh token was not persisted/rotated, so refresh fails.
- A reinstall minted new tokens and orphaned the old one.
- Slack auto-revoked a token it detected as leaked.
Read the exact error: refresh on token_expired (persisting the rotated refresh token), reinstall or re-OAuth on token_revoked — then update the secret store and confirm with auth.test.
Download the Free 500-Prompt DevOps AI Toolkit
500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.
- 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
- Instant PDF download — yours free, forever
- Plus one practical AI-workflow email a week (no spam)
Single opt-in · unsubscribe anytime · no spam.