SaaS API tokens are standing credentials that bypass single sign-on and MFA, and most organisations cannot say how many exist, who owns them or what they can reach. A Slack bot token, a GitHub personal access token or a Salesforce connected app refresh token keeps working after the person who created it has moved on, and attackers know it: the Salesloft Drift, Klue and 2022 GitHub OAuth incidents were all carried out with valid tokens rather than broken passwords. This guide explains the token types on three of the most widely connected platforms, the settings that limit them, and how to run a token lifecycle from issue to revocation. It is for identity, SaaS security and platform engineering teams who administer these tenants. Broader OAuth app governance and Salesforce hardening have their own guides; this page focuses on the tokens themselves.
Key takeaways
- Every token is a non-human identity. Give each one an owner, a purpose, a scope and an expiry, and record it in an inventory you can query during an incident.
- Prefer tokens that expire on their own. Slack token rotation gives 12-hour access tokens, GitHub fine-grained PATs default to 30 days, and Salesforce refresh token policy can replace "valid until revoked".
- Scope beats secrecy. A fine-grained PAT limited to one repository, or a connected app restricted to pre-authorised users, limits the damage when the token leaks, which it eventually will.
- Admin policy is where control lives. GitHub organisation PAT policies, Salesforce Permitted Users and the block on uninstalled connected apps work even when individual users make poor choices.
- Revocation must be rehearsed. When a vendor holding your tokens is breached, you need to revoke and rotate in hours, then review API logs for the exposure window.
SaaS API token types compared
Each platform names its tokens differently, but they fall into three groups: tokens that act as a user, tokens that act as an app or bot, and refresh tokens that mint new access tokens.
| Platform | Token | Prefix or form | Acts as | Default lifetime | Main admin control |
|---|---|---|---|---|---|
| Slack | Bot token | xoxb- | The app's bot, not a person; survives the installer's deactivation | No expiry unless token rotation is enabled | App approval, scopes, token rotation |
| Slack | User token | xoxp- | The workspace member who authorised the app | No expiry unless rotation is enabled | App approval, user scope review |
| Slack | App-level token | xapp-; rotating variant xoxe.xapp- | The app across every organisation where it is installed | Rotating variant: 12 hours | Limit who can create apps and app-level tokens |
| Slack | Workflow token | xwfp- | A just-in-time subset of the bot token | 15 minutes, no refresh | Workflow and function permissions |
| GitHub | Fine-grained PAT | Single owner, selected repositories | The user, limited to granted permissions | 30 days (1 to 366 days, or none if policy allows) | Organisation approval and maximum lifetime |
| GitHub | Classic PAT | ghp_ | The user, across every repository and organisation they can reach | User chooses; no expiry requirement by default | Restrict PAT access, maximum lifetime |
| GitHub | OAuth and app tokens | gho_, ghu_, ghs_, refresh ghr_ | OAuth app on behalf of a user, or a GitHub App | Varies by type | OAuth app access policy, GitHub App installation permissions |
| Salesforce | Connected app access and refresh tokens | OAuth 2.0 tokens issued to a connected app | The authorising user, through the app | Refresh token valid until revoked by default | Permitted Users, refresh token policy, IP relaxation |
| Atlassian Cloud | API token (scoped or unscoped) | Used with account email over basic auth | The account that created it | One year (1 to 365 days) | Scoped tokens, service accounts. See the Atlassian Cloud Security Guide. |
Recognisable prefixes matter for defenders. GitHub introduced prefixes such as ghp_ and a 32-bit checksum in the last six characters in April 2021 so scanners can identify tokens reliably and reject random strings offline. Slack's xox prefixes serve the same purpose. Platforms that issue opaque, unprefixed tokens are harder to detect in code and logs.
Slack tokens: bots, users and rotation
- Prefer bot tokens to user tokens: a user token writes as the person who authorised it and carries their access; a bot token is tied to the app and keeps working if the installing user is deactivated. That second property is an advantage for continuity and a risk for ownership, so record a team owner for every bot.
- Turn on token rotation for new apps: without rotation a Slack access token never expires. With rotation, access tokens expire every 12 hours and each refresh token is single-use. Slack documents that rotation cannot be turned off once enabled, so test it with the app's real deployment before enabling in production. Bolt handles rotation automatically.
- Treat app-level and configuration tokens as administrative: an app-level token represents the app in every organisation where it is installed, and configuration tokens can create and configure apps through the manifest APIs. Keep both out of chat, tickets and shared documents.
- Retire legacy tokens: Slack advises against legacy bot, workspace and custom integration tokens. Find and replace any that remain, along with long-lived service tokens where a rotating option exists.
- Control installation: restrict who can install apps and request scopes, and review user-token scopes such as message history with particular care, because they expose everything the user can see. See the Collaboration Tool Security Guide.
GitHub personal access tokens and their alternatives
Fine-grained versus classic
- Fine-grained by default: GitHub recommends fine-grained PATs wherever they can do the job. They are limited to one user or organisation, can be restricted to selected repositories and carry per-resource read, write or admin permissions. Each account can hold up to 50.
- Know the gaps: fine-grained PATs cannot yet contribute to public repositories where the user is not a member, act for outside collaborators, access several organisations at once, or reach Packages and the Checks API. These gaps are the usual reason classic tokens survive, so document each exception.
- Classic tokens are broad: a classic PAT with the
reposcope reaches every repository the user can access across every organisation. One leaked classic token from a maintainer with many memberships has a far larger blast radius than its owner usually realises.
Organisation policy
- Restrict classic PATs: organisation owners can block PAT access to organisation resources. Requests from blocked tokens fail with HTTP 403.
- Keep approval on: "Require administrator approval" is the default for fine-grained PATs. A token awaiting approval stays pending and can read only public resources.
- Set a maximum lifetime: the default maximum for fine-grained PATs is 366 days and classic PATs have no requirement by default. Owners can set a shorter maximum for both. Non-compliant tokens are blocked from the organisation rather than revoked, so users find out when their calls fail: announce the change first.
- Review active tokens: owners can see and revoke fine-grained PATs under Settings, Personal access tokens, Active tokens, filtered by owner, repository or permission. Classic PATs cannot be viewed or revoked there, which is another reason to restrict them. Revoking a token does not remove SSH keys it created, so check those separately.
Use something other than a PAT where you can
- In workflows: use the built-in
GITHUB_TOKEN, which GitHub recommends over a PAT. - For automation and integrations: a GitHub App with installation-scoped permissions and short-lived installation tokens is usually better than a PAT tied to a person.
- On the command line: GitHub CLI or Git Credential Manager avoids copying a PAT into files.
- Stop leaks at the source: push protection blocks recognised secrets on pushes from the command line, web commits, uploads and the REST API. Bypasses require a reason and are written to the audit log; delegated bypass lets you require review instead. See the Git Secret Scanning Guide and the GitHub and GitHub Actions Security Guide.
Salesforce connected app tokens
A connected app is how an external application obtains OAuth access to Salesforce. Its policies decide who can authorise it, where its tokens can be used and how long its refresh tokens last.
| Setting (OAuth Policies) | Default | Safer choice | Why |
|---|---|---|---|
| Permitted Users | All users may self-authorize | Admin approved users are pre-authorized, assigned through a permission set | Stops any user approving an app on first use, the step vishing campaigns rely on |
| IP Relaxation | Enforce IP restrictions | Keep enforced; relax only for refresh tokens if a documented integration needs it | Stolen tokens used from attacker infrastructure are refused; JWT and SAML bearer flows always enforce IP restrictions |
| Refresh Token Policy | Refresh token is valid until revoked | Expire refresh token after a fixed period, or if not used for a set period | Bounds the life of a token held by a vendor or a forgotten integration |
| Uninstalled connected apps | Blocked for end users by Salesforce (announced for September 2025) | Install trusted apps, block the rest, grant "Approve Uninstalled Connected Apps" to few people | Users can no longer connect arbitrary apps, and device-flow apps are blocked even for earlier users |
- Watch the bypass permission: the "Use Any API Client" permission bypasses the Permitted Users restriction. Assign it only to named integration users, and note that custom profiles cloned from System Administrator do not automatically receive "Approve Uninstalled Connected Apps".
- Review usage: the Connected Apps OAuth Usage page in Setup lists every app with active tokens, its user count and an Install or Block action. Blocking an app ends its sessions and prevents new ones.
- Give integrations their own users: run each integration under a dedicated integration user with only the objects and fields it needs, so its tokens cannot reach data a human administrator could.
Profile, permission set and broader Salesforce hardening are covered in the Salesforce Security Guide.
The API token lifecycle
| Stage | Control | Evidence to keep |
|---|---|---|
| Request and issue | Named owner, business purpose, least scope, expiry set at creation; app or bot token preferred to a personal one | Ticket or approval record linked to the token identifier |
| Store | Secrets manager or platform secret store; never in code, chat, tickets or CRM records | Secret path and access policy |
| Use | IP restrictions where supported, dedicated integration accounts, monitoring of call volume and source | Audit and API logs retained for the investigation window |
| Rotate | Platform rotation (Slack, short-lived GitHub App tokens) or scheduled replacement before the maximum lifetime | Last rotation date per token |
| Review | Quarterly attestation by owner; automatic flag for tokens unused for 90 days | Attestation record |
| Revoke | On owner leaving, project end, vendor incident or anomaly; check for artefacts the token created (SSH keys, webhooks, apps) | Revocation time and follow-up log review |
- Inventory first: pull the token lists each platform offers (GitHub active fine-grained tokens, Salesforce Connected Apps OAuth Usage, Slack installed apps and Atlassian service accounts) into one register keyed by owner and application. See the SaaS and OAuth App Governance Guide.
- Tie tokens to the leaver process: deactivating a user does not always remove the tokens or apps they created. Slack bot tokens survive by design and classic GitHub PATs are invisible to organisation owners. See the Employee Offboarding Security Guide.
- Close pilots properly: a token issued for a trial or a one-off migration is the token most likely to be forgotten. Put an end date on it at issue.
Choosing the right credential
| Need | Prefer | Avoid | Trade-off |
|---|---|---|---|
| CI job writing to one repository | GITHUB_TOKEN or a GitHub App | Maintainer's classic PAT | App setup takes longer but removes personal ownership |
| Internal tool reading several repositories | GitHub App or fine-grained PAT limited to those repositories | Classic PAT with repo | Fine-grained PATs cannot span organisations |
| Slack bot posting alerts | Bot token with minimal scopes and rotation | User token of the engineer who built it | Rotation needs refresh handling in the app |
| Vendor integration into Salesforce | Connected app, admin pre-authorised, dedicated integration user, refresh token expiry | Self-authorised app using an administrator's account | Expiring refresh tokens may require re-authorisation |
| Script calling Jira or Confluence | Scoped token on an Atlassian service account | Unscoped token on a personal account | Some apps do not yet support scopes |
Small organisations: start with the platform defaults that already help (GitHub fine-grained approval, Salesforce uninstalled-app blocking), set maximum lifetimes and keep a single spreadsheet register. Large organisations: automate collection from each platform's API, feed the register into identity governance for owner attestation, alert on new high-privilege tokens and give a central team authority to revoke without waiting for the owner. See the API Key Management Guide.
How to implement: a phased approach
- Discover (weeks 1 to 2): export tokens, installed apps and connected apps from each platform, and run secret scanning across code, wikis and ticketing systems for prefixed tokens.
- Assign owners: map each token to a person and a team. Tokens without a reachable owner go on a revocation list with a notice period.
- Apply policy in report mode: announce GitHub maximum lifetimes and classic PAT restrictions with a date; in Salesforce, review Connected Apps OAuth Usage and install or block each uninstalled app.
- Pilot stricter settings: move one connected app to "Admin approved users are pre-authorized" and an expiring refresh token policy; enable Slack rotation on one bot. Confirm the integration still works through a full refresh cycle.
- Enforce in rings: extend to remaining integrations by risk, highest data access first. Roll back by restoring the previous policy value on the single app, not by relaxing the tenant.
- Replace personal tokens: migrate automation from personal PATs and user tokens to GitHub Apps, bot tokens and integration users.
- Rehearse revocation: run a tabletop of "a vendor holding our tokens is breached": revoke, rotate exposed secrets and review the logs, and time each step.
Detection and telemetry
- Token creation and approval: GitHub pending and active fine-grained token lists and audit log records of push protection bypasses; new Slack app installs and scope changes; new Salesforce connected app authorisations.
- Unusual use: API calls from new IP ranges, hosting providers or anonymising networks; unfamiliar user agents; bulk exports or repository clones outside the token's normal pattern.
- Data access volume: Salesforce event monitoring for large query and export activity by integration users, and GitHub clone volume per token.
- Leaked tokens: secret scanning alerts in code, plus scanning of support cases and CRM text, where customers and staff paste credentials.
| Metric | Target |
|---|---|
| Tokens and connected apps with a named, active owner | 100% |
| GitHub tokens with expiry within policy | 100%, with classic PATs restricted or listed as exceptions |
| Connected apps with "Admin approved users are pre-authorized" | All apps with access to customer data |
| Tokens unused for 90 days still active | Zero after each review cycle |
| Time to revoke all tokens for a named vendor | Measured in hours in the last rehearsal |
| Push protection bypasses per month | Falling, each with a reviewed reason |
Threats and controls mapped to frameworks
| Threat (MITRE ATT&CK v20) | Control on this page | NIST SP 800-53 Rev. 5 | NIST CSF 2.0 |
|---|---|---|---|
| T1528 Steal Application Access Token | Short lifetimes, rotation, tokens held in a secrets manager | IA-5 Authenticator Management | PR.AA-01 |
| T1550.001 Application Access Token (reuse of stolen tokens) | IP restrictions, anomaly monitoring, revocation playbook | AU-6, CA-7 | DE.CM-09 |
| T1199 Trusted Relationship (vendor-held tokens) | Vendor token inventory, refresh token expiry, rehearsed revocation | SA-9 External System Services, SR-3 | ID.AM-02 |
| T1552.001 Credentials In Files | Push protection, secret scanning, no tokens in tickets or CRM | IA-5 | PR.AA-01 |
| T1213 Data from Information Repositories and T1567 Exfiltration Over Web Service | Least scope, integration users, export monitoring | AC-6 Least Privilege | PR.AA-05 |
| T1078.004 Cloud Accounts | Owner attestation, leaver process covering tokens | AC-2 Account Management | PR.AA-01 |
The same controls sit under CIS Controls v8.1 Control 5 (Account Management), Control 6 (Access Control Management) and Control 15 (Service Provider Management), and ISO/IEC 27001:2022 Annex A 5.17 (Authentication information) and 5.19 (Information security in supplier relationships). OWASP API Security Top 10 2023 API2 (Broken Authentication) covers the provider side of token handling. See the API Security Guide.
Common failure patterns
- A pilot token nobody revoked: a GitHub personal access token given to a third party for a limited pilot in 2022 stayed active with write access to code. In 2026 it was used to plant code in Klue's integration service that harvested customers' Salesforce OAuth tokens. See the Klue OAuth Breach 2026.
- Self-authorisation left on: callers posing as IT support talked staff through connecting a modified Data Loader app, which then acted as a persistent API identity without the employee's password or MFA. See the ShinyHunters Salesforce Data Theft Campaign 2025.
- Secrets pasted into records the token can read: attackers with CRM access searched exported support cases for AWS keys and Snowflake tokens to reach further systems.
- Classic PATs left unrestricted: owners cannot see them, so the organisation cannot revoke them during an incident without the user's help.
- Revocation without follow-through: revoking a token but leaving the SSH keys, webhooks or OAuth apps it created, or not reviewing what it did during the exposure window.
Lessons from incidents
- Vendor-held tokens are your tokens: in the Salesloft Drift breach an intruder moved from Salesloft's GitHub account into Drift's AWS environment, took customers' integration tokens and exported Salesforce data from many organisations between 8 and 18 August 2025, before all Drift tokens were revoked on 20 August. No user was phished. See the Salesloft Drift Breach 2025.
- OAuth grants to developer tools reach code: in April 2022 attackers used OAuth user tokens issued to the Heroku Dashboard and Travis CI apps to clone private repositories, including npm's, then used an AWS key found in one of them. GitHub advised removing unneeded OAuth apps and scanning private repositories for secrets. See the GitHub OAuth Token Breach 2022.
- The common thread: each attacker held a valid token with more scope and life than the job needed, and each victim's fastest lever was revocation it had to perform under pressure.
Practitioner checklist
- Build one register of SaaS API tokens, bots and connected apps with owner, scope, expiry and data reach.
- Restrict classic GitHub PATs, keep fine-grained approval on and set a maximum lifetime well under 366 days.
- Move automation to
GITHUB_TOKEN, GitHub Apps, Slack bot tokens and Salesforce integration users instead of personal tokens. - Enable Slack token rotation for new and updated apps after testing a full refresh cycle.
- Set Salesforce connected apps to "Admin approved users are pre-authorized" with an expiring refresh token policy and enforced IP restrictions.
- Review Connected Apps OAuth Usage, install trusted apps and block the rest; limit "Approve Uninstalled Connected Apps" and "Use Any API Client".
- Turn on push protection and scan tickets, CRM text and wikis for prefixed tokens.
- Revoke tokens unused for 90 days and tokens whose owner has left, including bot tokens they built.
- Keep a per-vendor revocation runbook and rehearse it at least once a year.
Standards and references
- GitHub Docs: Managing your personal access tokens
- GitHub Docs: Setting a personal access token policy for your organization
- GitHub Docs: About push protection
- Slack Developer Docs: Tokens
- Slack Developer Docs: Using token rotation
- Salesforce Help: Connected App OAuth Access Policies
- Salesforce Help: Connected App Usage Restrictions for Uninstalled Apps
- MITRE ATT&CK: Steal Application Access Token
Related NHI Mgmt Group resources: SaaS and OAuth App Governance Guide · Salesforce Security Guide · Secrets Management Guide · Token Lifetime Policy Design Guide · Human vs Non-Human Identity