Say Goodbye to Personal Access Tokens (PATs) in Azure DevOps: Practical Migration Strategies
In this post, Michael Thomsen discusses how his team eliminated all Azure DevOps Personal Access Tokens (PATs). He details practical migration steps, leveraging service principals and workload identity federation, making it a must-read for DevOps professionals focused on secure automation.
Say Goodbye to Your Personal Access Tokens
Author: Michael Thomsen
Michael Thomsen, an established author of Azure DevOps Extensions, shares his team’s migration journey away from Personal Access Tokens (PATs) in Azure DevOps automation pipelines, inspired by Jesse Houwing’s guidance and resources.
Introduction
As a team extensively using Azure DevOps REST APIs, we at Agile Extensions relied on PATs for various automation scenarios—until recently. Thanks to community help (especially Jesse Houwing’s blog post), we’ve now eradicated PATs, improving automation security and reducing maintenance overhead.
Credit
This transformation was made possible thanks to direct help and resources shared by Jesse Houwing. If you want to deepen your knowledge, check Jesse’s guide on publishing marketplace extensions without PATs.
The 5 Scenarios Where We Used PATs
We previously used PATs (Personal Access Tokens) for these scenarios:
- Publishing Bravo Notes extension for development, staging, and production (via Azure Pipelines/Marketplace APIs)
- Retrieving marketplace event data (via Azure Functions on a schedule)
- Running integration tests for Bravo Notes components (in Azure Pipelines)
- Running end-to-end (e2e) tests outside Azure DevOps (in Azure Pipelines)
- Running integration/e2e tests locally
Manually managing PATs was tedious and error-prone, requiring regular manual renewal and secret management.
PAT REST APIs—A Dead End
We first considered automating PAT renewal using the new PAT REST APIs. However, thanks to Jesse’s advice, we realized there was a better path—using an Azure Service Principal with workload identity federation.
The Modern Approach: Workload Identity Federation & Service Principals
This modern authentication scheme uses Azure AD service principals and ARM service connections, providing:
- Automated token acquisition
- Fine-grained permissions
- Reduced secret management overhead
Migrating Each Scenario
Scenario 1: Publishing Marketplace Extensions
- Create an ARM Service Connection (Choose “App registration (automatic)” and “Workload identity federation”)
- Add the app registration/service principal as a user in Azure DevOps
- Extract the Azure DevOps Identity ID from the Profile API via pipeline task
- Add the App registration as a marketplace publisher member
- Update pipeline to use the ARM service connection
-
Use the latest marketplace extension tasks (v5), e.g.:
- task: PublishAzureDevOpsExtension@5 displayName: 'Publish Extension' inputs: connectTo: 'AzureRM' connectedServiceNameAzureRM: 'marketplace-service-connection' fileType: vsix vsixFile: '$(Pipeline.Workspace)/vsix/production.vsix' updateTasksVersion: false
Now, no more PATs needed for extension publishing.
Scenario 2: Azure Function App API Calls
- Add the Azure Function app as a user in Azure DevOps
-
Use Azure Managed Identity to obtain an access token (Node.js sample):
const { ManagedIdentityCredential } = require("@azure/identity"); async function getMarketplaceAccessToken() { const credential = new ManagedIdentityCredential({ clientId: process.env.AZURE_CLIENT_ID, }); const tokenResponse = await credential.getToken( "499b84ac-1321-427f-aa17-267ca6975798/.default", { tenantId: process.env.AZURE_TENANT_ID } ); return tokenResponse.token; }
Scenario 3: Integration Tests in Azure Pipelines
- Create a dedicated ARM service connection/application registration for integration testing
-
Retrieve the access token via Azure CLI in the pipeline:
- task: AzureCLI@2 displayName: 'Acquire token for integration testing' inputs: azureSubscription: 'azure-devops-integration-testing-connection' scriptType: 'pscore' scriptLocation: 'inlineScript' useGlobalConfig: true inlineScript: | $accessToken = az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query "accessToken" --output tsv write-host "##vso[task.setsecret]$accessToken" write-host "##vso[task.setvariable variable=SECRET_INGETRATION_TESTING_TOKEN;issecret=true]$accessToken"
- Use the token in subsequent tasks—no PATs needed.
Scenario 4: E2E Tests in Azure Pipelines (Across Orgs)
- Add the application registration/service principal as a user in the target test Azure DevOps organization
- Grant it the required permissions
- Use the same Azure CLI approach to acquire tokens for cross-org API calls
Scenario 5: Local Integration and E2E Tests
- Use Azure Developer CLI for interactive login and token retrieval:
- Modify test script:
azd auth login && npx jest --config jest.integration.config.js
-
Retrieve access token programmatically if not running in CI:
let token = process.env.SECRET_INGETRATION_TESTING_TOKEN; if (!token && !process.env.CI) { const credential = new AzureDeveloperCliCredential({ tenantId: process.env.AZURE_TENANT_ID, }); const tokenResult = await credential.getToken( '499b84ac-1321-427f-aa17-267ca6975798/.default', { tenantId: process.env.AZURE_TENANT_ID } ); token = tokenResult.token; }
- Modify test script:
Bonus: Renovate Pipeline Token
- Renovate can accept an OAuth token in place of a PAT. Use the same Azure CLI workflow to generate a token and supply it to the
RENOVATE_TOKEN
environment variable. - Azure DevOps now accepts OAuth tokens even with
Basic
auth headers.
Key Learnings & Wrapping Up
- ARM service connections, OpenID Connect, workload identity federation, service principals, and app registrations are the future of secure Azure DevOps automation
- PATs are simple, but not suitable for robust or scalable automation
- Migration is more accessible than it seems, especially with shared community resources
Acknowledgements
Special thanks to Jesse Houwing and Joost Voskuil for critical guidance, and to the Azure DevOps Club for community support.
If you’re facing similar challenges with Azure DevOps or GitHub, consider joining the Azure DevOps Club.
This post appeared first on “Jesse Houwing’s Blog”. Read the entire article here