Azure DevOps Global PAT Retirement: The December 1 Cutoff You Can't Audit

Every Azure DevOps personal access token scoped to all accessible organizations stops working on December 1, 2026, and the platform never logged which ones are in use. The inventory query, the replacement per integration type, and the policies that stop it recurring.

By VVV Ops ·

If a pipeline, a package restore, or a self-hosted agent in your estate authenticates with an Azure DevOps personal access token scoped to "all accessible organizations", it stops working on December 1, 2026. The Azure DevOps global PAT retirement has no extension path and no grace period published. The awkward part is the audit: Azure DevOps does not log token usage, so you cannot ask the platform which of these tokens are load-bearing. You have to find them by their shape, not by their traffic. The work splits into an inventory pass, a replacement decision per integration type, and two policy toggles.

What actually stops working, and what does not

Microsoft's retirement notice and the PAT documentation agree on the scope. Only the global PAT type is going away: a token a user created with the organization selector set to every organization they can reach. Organization-scoped PATs are unaffected and remain a supported option. Azure DevOps Server keeps global PATs; this is a Services-only change.

One detail decides how much work you have ahead of you. Microsoft originally planned to block creation of new global PATs on March 15, 2026, then cancelled that step in a March 5 update to the notice. Creation stayed open all year. So the population of global PATs in your tenant is not frozen at its March size, and any runbook or onboarding doc that says "create a PAT, tick all organizations" has been quietly adding to the pile for seven months. Check your internal wiki before you check your tokens.

Find them by shape, because usage is not logged

The portal view works for one person. Sign in at https://dev.azure.com/{organization}, open user settings, select Personal access tokens, then set Access scope to All accessible organizations and Status to Active. That is a per-user list, and nobody is going to run it for 300 engineers.

The PAT Lifecycle Management API is the programmatic route, with two constraints that shape your plan. It needs a Microsoft Entra access token from a user-delegated flow with the vso.pats scope, and it only ever returns the calling user's own tokens. There is no tenant-wide listing.

There is also no allOrgs field in the list response, which trips people up. A global PAT is identified by targetAccounts being null, documented as "null if the token applies to all of the user's accessible organizations". An organization-scoped token carries an array of organization GUIDs instead.

# Run as yourself. Entra access tokens last one hour.
TOKEN=$(az account get-access-token \
  --resource 499b84ac-1321-427f-aa17-267ca6975798 \
  --query "accessToken" -o tsv)

curl -sS -H "Authorization: Bearer $TOKEN" \
  "https://vssps.dev.azure.com/acme-engineering/_apis/tokens/pats?displayFilterOption=active&\$top=100&api-version=7.1-preview.1" \
| jq -r '.patTokens[]
         | select(.targetAccounts == null)
         | [.displayName, .scope, .validTo, .authorizationId] | @tsv'

The resource GUID 499b84ac-1321-427f-aa17-267ca6975798 is the Azure DevOps application ID, taken from Microsoft's Entra token guidance for the Azure CLI. $top caps at 100, so follow continuationToken in larger tenants. A scope of app_token means the token is also full-scoped, which moves it to the front of the queue.

For the tokens nobody will claim, the audit log is the next stop. Organization settings then Auditing carries Token.PatCreateEvent, Token.PatUpdateEvent, Token.PatRevokeEvent and Token.PatPublicDiscoveryEvent, which tell you who created a token and when. Retention is 90 days and is not configurable, so for anything older you need an export or an existing audit stream to your SIEM. The documentation is blunt that token access events are not logged, which means the log cannot tell you whether a PAT is still in use. Microsoft's own MCP example prompts suggest asking an assistant "when each was last used"; that data does not exist, and an assistant that answers confidently is guessing.

We would not try to prove a token is dead. Revoke in waves with a rollback path, starting with the tokens whose owner has left.

A grep across repositories and pipeline definitions catches what the API misses, because PATs have a fixed shape: 84 characters, 52 of them random, with the literal AZDO signature at positions 76 through 80.

# Catches the token format in checked-in files and pipeline YAML.
rg -n --no-heading -e '[A-Za-z0-9]{75}AZDO[A-Za-z0-9]{4}' .

That pattern finds the token, not its scope, so treat every hit as a rotation candidate. If you do not already have server-side secret scanning in the pipeline, our DevSecOps pipeline guide covers where that gate belongs.

Pick the replacement per integration, not per team

Every global PAT falls into one of five buckets, and the right answer differs for each. The reflex fix, swapping a global PAT for an organization-scoped PAT, is correct for exactly one of them.

| Integration | Replace with | Effort | Watch out for | |---|---|---|---| | Self-hosted agent registration | Service principal (--auth SP) | Low, one reconfigure per agent | Needs agent 3.227.1 or newer; auth is used at registration only | | REST API automation and scripts | Managed identity or service principal, Entra bearer token | Medium | Application identities cannot create PATs or SSH keys | | Pipeline access to Azure resources | Workload identity federation service connection | Medium | A second deadline applies, see below | | Azure Artifacts package clients | Artifacts Credential Provider, or org-scoped PAT with packaging scope | Low | A PAT cannot be used as a NuGet API key | | Third-party tools without Entra support | Organization-scoped PAT, minimum scopes, short lifetime | Low per tool, high in aggregate | One PAT per organization, so multi-org tools need several |

For anything that authenticates to AWS from a pipeline, the federation pattern is the same one we described in Terraform security best practices for AWS: the runner presents a short-lived identity token and gets scoped credentials back. This post is the Azure DevOps control-plane half of that story.

Self-hosted agents are the easy win, so do them first

Agent registration is the bucket most teams fear and the one that costs the least. The authentication method is used only during registration, not during everyday operation, so there is no steady-state credential to rotate. Azure DevOps Services supports three registration types today: personal access token, device code flow, and service principal.

Service principal registration landed in agent version 3.227.1, so an estate on the 4.x agent already has it.

# Illustrative values. Replace with your own; acme-engineering is not a real org.
./config.sh --unattended \
  --url https://dev.azure.com/acme-engineering \
  --auth SP \
  --clientId "$AZDO_SP_CLIENT_ID" \
  --tenantId "$AZDO_SP_TENANT_ID" \
  --clientSecret "$AZDO_SP_CLIENT_SECRET" \
  --pool linux-x64 \
  --agent "$(hostname)" \
  --replace \
  --work _work

The service principal needs the Administrator role on the agent pool, the same requirement the PAT flow had. Registration still takes a client secret, and managed identity is not one of the three registration options, so the secret lives in your secret store and gets injected at provisioning time, never baked into the image. The agent does not keep it afterwards. Device code flow is fine for a handful of hand-built machines and wrong for anything you provision from an image.

The bucket with no clean answer: automation that mints PATs

Some internal tooling creates PATs on behalf of users, usually onboarding scripts or an internal developer portal that hands out credentials. There is no drop-in replacement, and this is the one place we would plan for a rewrite rather than a swap.

Microsoft is explicit that service principals and managed identities cannot create or manage PATs because they do not represent a user. The application identity documentation states they "can't create PATs or SSH keys, create organizations, or use Azure DevOps OAuth flows". The Lifecycle Management API enforces the same rule from the other side: it needs a user-delegated flow. So a token-vending service cannot run as an app identity, full stop.

Two honest options. Delete the vending machine and give each consuming workload its own Entra application identity, which is more objects to govern but removes a credential broker from your trust boundary. Or keep a user-delegated flow and accept that a named human's consent sits in the path, with the operational consequences that brings. We pick the first for anything touching production. The reasoning is the same one we applied to pipeline agents in Trust boundaries for AI agents in CI/CD: a component that can issue credentials for other components is the highest-value target in the system.

Two smaller details land in this bucket. Application identities consume a license in every organization where they hold a paid access level, and multi-organization billing does not apply to them, so fanning out one PAT into twelve app identities has a real line-item cost. And Azure Repos access needs Basic access or higher; Stakeholder will not do.

Turn the policies on, or you will do this again in 2027

The retirement removes today's global PATs. It does not stop your tenant from accumulating the next generation of over-scoped, long-lived, unowned tokens. Four tenant policies are documented in Manage personal access tokens using policies, and three of the four ship off by default.

| Policy | Level | Default | Our recommendation | |---|---|---|---| | Restrict global personal access token creation | Tenant | Off | On, today. It makes the December cutoff a non-event for new tokens | | Restrict full-scoped personal access token creation | Tenant | Off | On, with a group allowlist rather than named users | | Enforce maximum personal access token lifespan | Tenant | Off | On, 90 days or shorter | | Automatically revoke leaked personal access tokens | Tenant | On | Leave on. Disabling it leaves tokens found in public GitHub repositories active |

Tenant policies need the Azure DevOps Administrator role and live under Organization settings then Microsoft Entra. The separate organization-level policy, Restrict personal access token (PAT) creation, needs Project Collection Administrator and sits under Organization settings then Policies. That one also blocks global PAT usage inside the organization, which gives you a per-organization kill switch to test with before December. Its Allow creation of PAT with packaging scope only checkbox exists because package clients are the laggards in Entra adoption, and it is the pragmatic setting for most organizations.

Use Microsoft Entra groups on every allowlist. Each policy keeps its own list, so exempting a team means adding the group four times. The documentation warns that a named user on an allowlist places a reference to their identity in the United States, Europe, and Singapore, which matters if you have data residency commitments.

The second deadline sitting behind this one

Teams that migrate pipeline authentication to workload identity federation this quarter should know there is a follow-up change already in flight, so you can do the work once.

| Date | Change | Who it affects | |---|---|---| | March 15, 2026 | Planned block on global PAT creation, cancelled | Nobody, but it is why your token count kept growing | | July 1, 2026 | Azure DevOps issuer https://vstoken.dev.azure.com deprecated | New WIF service connections already use the Entra issuer | | December 1, 2026 | All global PATs stop working | Every integration in the table above | | July 1, 2027 | Azure DevOps issuer reaches end of life | Existing single-tenant WIF connections in the Azure public cloud |

Microsoft's issuer retirement notice describes an Update button on each affected service connection, with a manual path through Create federated credential in when you cannot reach the underlying identity. Multi-tenant applications and the sovereign clouds are out of scope for now. Convert the connections while you are already in that UI for the PAT work.

One more expiry trap applies to the organization-scoped PATs you keep. In a Microsoft Entra-backed organization, a new PAT goes inactive if you do not sign in with it within 90 days. A token minted during a migration sprint and parked for a quarter will be dead when you reach for it.

What we would do with six weeks

Week one is inventory: run the API query per team lead, grep the repositories, and export the audit log before the 90-day window drops anything you need. Week two is the agent fleet, because it is mechanical and it proves the service principal path works. Weeks three and four are the long tail of third-party tools, one organization-scoped PAT each with the narrowest scope that works. Week five is the token-vending rewrite if you have one, and the policy toggles. Week six is quiet, which is the point of starting now. Flip the organization-level restriction policy in a low-traffic organization first and watch what breaks there instead of everywhere.

The failure mode we expect to see in December is not a missed token. It is a tool nobody remembered owning, authenticating as someone who left in 2024, discovered when a release fails.

When to Get Help

Credential migrations are unglamorous and they go wrong in the same places every time: an inventory that misses the tokens held by contractors, an agent fleet rebuilt by hand, a vending service that turns out to be load-bearing. If you want a second pair of eyes on the inventory, or someone to run the agent cutover while your team ships features, get in touch. We do this work on Azure DevOps, GitHub Actions, and GitLab, and we would rather help you in October than in December.

Tags: azure devops global pat retirement, azure devops personal access token migration, devsecops implementation, integrate security into ci/cd pipeline, security automation, ci/cd pipeline automation