Slack has already switched off legacy custom bots and has paused, but not cancelled, the retirement of classic apps, so most organisations still run integrations built on broad, user-scoped tokens that nobody has reviewed in years. Legacy custom bots stopped working on 31 March 2025. The classic apps shutdown moved three times during 2024 and 2025 and was then put on hold in December 2025, which many teams read as permission to leave those apps alone. That is a mistake: classic apps still depend on the umbrella bot scope and older OAuth behaviour, and Slack says they remain a legacy method that it strongly recommends migrating. This guide sets out the official timeline as Slack published it, how to find affected apps and the identities behind them, how the move to granular scopes works, and how to test and roll back. It is for Slack administrators, platform engineers and security teams who own Slack integrations. Token handling in general is covered in the Slack Tokens Security Guide, and workspace hardening in the Slack Enterprise Security Guide.
This is an independent guide from NHI Mgmt Group, based on Slack's public documentation as of November 2026. It is not sponsored or reviewed by Slack. Product features change, so confirm settings against Slack's current documentation.
Key takeaways
- Legacy custom bots are gone. Slack stopped them functioning from 31 March 2025; their API calls are rejected and Slack said their tokens would be revoked and the bots removed from channels.
- Classic apps are paused, not safe. On 8 December 2025 Slack paused the classic apps deprecation with no new date, while still calling classic apps a legacy method and recommending migration to avoid future interruptions.
- Nothing new can be built on the old models. Since 4 June 2024 nobody can create classic apps or legacy custom integration bot users, so every remaining instance is old and probably under-owned.
- Granular scopes shrink the blast radius. The umbrella
botscope pre-checks everything it covered; migration is the moment to uncheck what the integration does not use. - Migration is one way in practice. Once an app's configuration moves to granular scopes, the V1 OAuth endpoint stops working, and a rollback needs Slack's help and may be slow, so test on a staging app first.
What is changing and why
Slack has had three generations of integration. Legacy custom integrations, including custom bot users, were configured from a workspace's Configuration pages and issued tokens outside any app model. Classic apps introduced OAuth scopes but gave bots a single umbrella bot scope and often relied on the Real Time Messaging (RTM) API. Slack apps with granular permissions replaced them and are the only model Slack now develops.
The security difference is scope. A classic bot token carried everything the bot scope allowed, whether the integration needed it or not, and legacy custom integration tokens took on the full scope of the user who created them, according to Slack's token documentation. A granular Slack app requests individual scopes such as chat:write, channels:read or commands, and its bot token is not tied to the installing user, so the app survives that person leaving.
| Aspect | Legacy custom bot | Classic app | Granular Slack app |
|---|---|---|---|
| Status (checked 8 Nov 2026) | Discontinued 31 March 2025 | Legacy, deprecation paused since 8 December 2025 | Current model |
| Where configured | Workspace Configuration pages (my.slack.com) | api.slack.com/apps, labelled Classic | api.slack.com/apps or app manifest |
| Permission model | Legacy token, broad | Umbrella bot scope plus user scopes | Granular bot and user scopes |
| OAuth flow | None | V1 (oauth.access) | V2 (oauth/v2/authorize, oauth.v2.access) |
| Real-time events | RTM | RTM via rtm.connect | Events API over HTTP or Socket Mode |
| Custom name and icon | Yes | Yes by default | Needs chat:write.customize |
Official timeline and current status
Every date below comes from Slack's developer changelog and its feature retirements help article, checked on 8 November 2026. Slack moved the classic apps date repeatedly, so treat any future date as provisional until Slack publishes it.
| Date | Event | Source |
|---|---|---|
| December 2020 | Slack Marketplace stops accepting classic app submissions | Slack changelog, September 2024 entry |
| 27 May 2022 | Marketplace apps must use granular permissions | Slack changelog and migration guide |
| April 2024 | Slack announces the end of new creation of classic apps and legacy custom bots | Slack changelog, April 2024 |
| 4 June 2024 | No new classic apps or legacy custom integration bot users can be created | Slack changelog; feature retirements article |
| 30 September 2024 | Slack announces discontinued support for legacy custom bots and classic apps | Slack changelog, September 2024 |
| 7 November 2024 | Classic apps date moved to 31 March 2026 | Slack changelog |
| 31 March 2025 | Legacy custom bots no longer function | Slack changelog; feature retirements article (status Retired) |
| 11 April 2025 | Classic apps date moved to 25 May 2026 | Slack changelog |
| 29 July 2025 | Classic apps date moved to 16 November 2026 | Slack changelog |
| 8 December 2025 | Classic apps deprecation paused; classic apps continue to work for the foreseeable future; no new date | Slack changelog; feature retirements article (retirement on hold) |
Two points cause confusion. First, the struck-through text on the September 2024 changelog entry and older third-party summaries still show 16 November 2026 as the end date; the changelog entry of 8 December 2025 superseded that date. Second, the separate Legacy Workflow Builder retirement (announced 6 September 2023, retired 26 September 2024) is a different programme with its own migration, although it often appears in the same admin conversations.
Who and what is affected
- Former legacy custom bot owners: any script or service that still holds a legacy custom bot token has been failing since 31 March 2025. The risk now is the workaround: teams that replaced a dead bot with a personal user token (
xoxp-) to get things working again. - Classic app owners: internal tools, ChatOps bots and old vendor integrations that never moved to granular scopes. They still work, but they hold umbrella permissions and may depend on RTM, which granular bot tokens cannot use.
- Distributed app developers: classic apps installed in other organisations need code changes for the V2 OAuth flow and reinstallation by each customer.
- Admins and security teams: every remaining classic app is a non-human identity with broad access, frequently created by someone who has since left. Slack can preserve an app's token when its installer leaves, which the audit log records as
app_token_preserved. - Webhook and slash command consumers: in granular apps these attach to the bot user, so revoking the bot token can remove associated webhooks and slash commands; plan their re-creation.
Finding affected systems and identities
Build one inventory that joins the Slack side (which integrations exist) with the infrastructure side (where their tokens live and who owns them). The step-by-step audit procedure is in How to audit Slack apps, bots and tokens; this section covers what is specific to the retirement.
- Admin Deprecations tab: Slack directs workspace and org admins to the Deprecations tab in workspace or organisation settings to see affected integrations. Export it as the starting list.
- Developer views: legacy custom bots are listed under Configuration at my.slack.com, and classic apps carry the Classic label at api.slack.com/apps. Ask every team that builds on Slack to check both while signed in.
- Audit Logs API (Enterprise plans): query app actions with a token holding
auditlogs:read, installed by the organisation Owner. Useful actions areapp_installed,app_uninstalled,app_scopes_expanded,app_token_preserved,bot_token_upgraded(moved to granular permissions) andbot_token_downgraded(moved back). An app with nobot_token_upgradedevent and old install dates is a candidate classic app. - Code and secret stores: search repositories, CI variables and secrets managers for Slack token prefixes. Classic and legacy tokens typically appear as
xoxb-orxoxp-strings used with RTM or V1 OAuth code paths, so also search forrtm.connect,rtm.start,oauth.accessand theas_userparameter. Treat any hit as a secret to rotate, not just a line to fix. - Owner attribution: for each integration, record a named human owner, the service identity that runs it, the scopes it holds and the channels it can read. Integrations with no owner are candidates for removal rather than migration.
| Signal | Where to look | What it suggests |
|---|---|---|
| App labelled Classic | api.slack.com/apps | Umbrella bot scope, V1 OAuth |
| Entry under Configuration | my.slack.com workspace settings | Legacy custom integration, possibly non-functional |
app_token_preserved | Audit Logs API | Installer left, token kept alive; check ownership |
bot_token_downgraded | Audit Logs API | App moved back to non-granular permissions; investigate why |
rtm.connect or oauth.access in code | Source repositories | Classic app code path that will break on migration |
Personal xoxp- token in a service | Secrets manager, CI variables | Workaround for a dead legacy bot; acts as a human |
Migration options
Choose per integration. The right answer for a ten-year-old ChatOps bot used by one team is often deletion.
| Option | When it fits | Trade-offs |
|---|---|---|
| Retire the integration | No owner, no recent use, function duplicated elsewhere | Lowest risk; confirm nothing depends on its webhooks or slash commands |
| Update the classic app in place (Update to Granular Scopes) | Internal app installed only in its development workspace | No code changes for scopes on that workspace; RTM use must be replaced |
| Build a new granular Slack app | Former legacy custom bots; heavily changed classic apps | Clean scope design and manifest; new bot identity, channels must be re-joined |
| Migrate a distributed app with V2 OAuth | Apps installed in other organisations | Code change, staging app, customer reinstall, short install gap at switchover |
| Replace with a vendor's current integration | Old third-party classic integrations | New consent screen to review; remove the old app afterwards |
Mechanics of the granular scope update
- Scope selection: the Update to Granular Scopes tool, in the Tools section of the app management page, does not choose scopes for you. Because the umbrella
botscope pre-checks all the scopes it covered, uncheck everything the app does not call. Webhooks needincoming-webhook, slash commands needcommands, posting to public channels without joining needschat:write.public, and custom display names needchat:write.customize. - Bot versus user tokens: request user scopes only where the app must act as a person. A granular install issues a bot token (
xoxb-) and no user token by default, and deactivating the installing user no longer affects the app. - Real-time events: granular bot tokens cannot use RTM. Distributed apps should move to the Events API; internal apps behind a firewall can use Socket Mode, which uses an app-level token (
xapp-) withapps.connections.open. App-level token rotation (xoxe.xapp-, 12 hour access tokens) is available to granular apps. - OAuth: distributed apps redirect to
oauth/v2/authorizeand exchange the code withoauth.v2.access, whose response has a different structure from V1, so parsing code must change. - Old installations: existing classic bot tokens keep working after a V2 install, and they are not converted automatically outside the development workspace. Each installation must reinstall, and the old token should then be revoked with
auth.revoke.
Machine identities created during migration need the same lifecycle discipline as any other: owner, purpose, scopes, rotation and a removal trigger. See NHI lifecycle automation.
Testing and rollback
- Create a staging app. Slack recommends a separate app such as
[app_name]-stagingwith the target scopes, so the production app stays unchanged while you test scopes, events and OAuth. - Exercise every function. Post, read, slash commands, webhooks, interactive messages and unfurls. A missing scope returns an API error naming the scope required; add only that scope.
- Deploy code before settings. For distributed apps, ship the V2 OAuth code first, then publish the app settings, which take effect almost immediately. Expect a short window where new installations fail.
- Cut over and revoke. Reinstall, confirm the audit log shows
bot_token_upgradedwhere expected, rotate any secret store entries, then revoke the old classic token. - Know the rollback limits. Once configuration is migrated the V1 OAuth endpoint stops working. Slack can roll an app back to its previous non-granular scopes if you confirm the scope list with it, but Slack describes the process as complicated and possibly delayed. Your practical rollback is the untouched production classic app plus its existing token, kept until the staging app is proven.
Risks of doing nothing
- Over-privileged identities stay live: an umbrella-scoped bot token can read and post far beyond its job, which turns one leaked token into broad workspace access (ATT&CK T1528 Steal Application Access Token, then T1550.001 Application Access Token).
- Unplanned outage: the pause has no end date and Slack warns of future service interruptions for apps that do not migrate. A short-notice resumption would hit every unmigrated app at once.
- Human tokens doing machine work: replacing a dead legacy bot with a personal
xoxp-token means the service acts as that person, inherits their channel access and breaks when they leave. Use a bot token owned by an app instead. - Orphans and preserved tokens: classic apps installed by former staff keep working on preserved tokens, outside any review.
- RTM dependency lock-in: the longer RTM code stays, the larger the rewrite when Slack resumes the timetable.
| Framework | Reference | How it applies |
|---|---|---|
| NIST SP 800-53 Rev 5 | CM-8, SA-22 | Inventory integrations; plan replacement of components the vendor no longer develops |
| NIST SP 800-53 Rev 5 | AC-6, IA-5, AC-2 | Least privilege scopes, token management, owner and removal of integration accounts |
| NIST CSF 2.0 | ID.AM-02, PR.AA-01, PR.AA-05 | Software and service inventory; managed credentials; reviewed permissions |
| MITRE ATT&CK v20 | T1528, T1550.001 | Theft and reuse of application tokens that migration narrows |
Practitioner checklist
- Export the admin Deprecations tab and the list of Classic apps, and record an owner for each.
- Search code and secret stores for legacy token use,
rtm.connect,oauth.accessandas_user. - Find personal
xoxp-tokens that replaced legacy custom bots and move those jobs to bot tokens. - Retire integrations with no owner or no recent activity instead of migrating them.
- Migrate on a staging app, unchecking every scope the
botumbrella pre-selected that the app does not use. - Replace RTM with the Events API or Socket Mode before changing scopes.
- Revoke old classic tokens with
auth.revokeafter reinstall and rotate stored secrets. - Alert on
bot_token_downgraded,app_scopes_expandedandapp_token_preservedin the Audit Logs API. - Re-check Slack's changelog quarterly for a resumed classic apps date.
Standards and references
- Slack: Discontinuing support for legacy custom bots and classic apps
- Slack: Classic apps deprecation paused
- Slack: Discontinuing new creation of classic apps and legacy custom integration bots
- Slack Help Center: Slack feature and plan retirements
- Slack: Migrating classic apps
- Slack: Tokens
- Slack: Audit Logs API methods and actions reference
- NIST: SP 800-53 Rev. 5 Security and Privacy Controls
Related NHI Mgmt Group resources: Slack Tokens Security Guide · Slack Enterprise Security Guide · How to audit Slack apps, bots and tokens · NHI lifecycle automation