Skip to content

Service Connections

ado-aw pipelines use service connections to mint Azure DevOps-scoped tokens at runtime. Scalar permissions.read / permissions.write values refer to Azure Resource Manager connections. Cross-organization repository writes use an Azure DevOps service connection backed by Entra workload identity federation.

The compiled pipeline uses AzureCLI@3 to call az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798. connection-type: azureRM emits the ARM task inputs; connection-type: azureDevOps emits the Azure DevOps service-connection inputs.

Connection Used by Purpose
Write (optional override) Stage 3 — SafeOutputs executor Override $(System.AccessToken) for cross-project writes, scoped cross-org repository writes, or named attribution
Read (optional) Stage 1 — Agent Query ADO APIs (work items, repos, builds)

The write service connection overrides $(System.AccessToken). Use an ARM connection for the existing scalar path or an Azure DevOps WIF connection for cross-organization repository writes.

  1. Go to your Azure DevOps Project → Project Settings → Service connections

  2. Click New service connection → Azure Resource Manager

  3. Choose your authentication method:

    The simplest option — Azure DevOps creates the app registration and credentials for you.

    • Select Service principal (automatic)
    • Choose an Azure subscription (the identity needs at least Reader on the subscription — this is only used for az login, not for ADO operations)
    • Scope to a resource group if preferred
    • Name the connection (e.g. ado-aw-write) — this is the value you’ll use in permissions.write
    • Click Save

    Azure DevOps creates an Entra ID app registration and configures everything automatically.

  4. Grant ADO permissions to the service principal. The identity behind the connection needs permission to perform write operations in Azure DevOps:

    • Go to Azure DevOps Organization Settings → Users
    • Add the service principal (search by its app registration name)
    • Set access level to Basic
    • Add it to a project-level group with the permissions your safe outputs need — Contributors is sufficient for most use cases (PRs, work items, branches, tags, wiki pages)
  5. Reference it in your agent front matter:

    permissions:
    write: ado-aw-write # ← name of the service connection you created

Create an Azure DevOps service connection backed by Entra workload identity federation. Add its service principal or managed identity to every target Azure DevOps organization in the same tenant and grant the required repository permissions. Then use expanded write configuration:

permissions:
write:
service-connection: ado-repository-writer
connection-type: azureDevOps
allow:
- organization: other-org
projects:
- project: Other Project
repositories: [target-repo]
repos:
- name: Other Project/target-repo
alias: target
organization: other-org
endpoint: ado-repository-writer

The repeated connection name is intentional: endpoint authenticates checkout, while permissions.write authorizes trusted Stage 3 REST writes.


Create the read service connection (optional)

Section titled “Create the read service connection (optional)”

If your agent needs to query Azure DevOps APIs (e.g. read work items, list PRs, fetch build results), create a second connection with read-only ADO permissions.

Follow the same steps as above, but:

  • Name the connection ado-aw-read (or similar)
  • In ADO, grant the service principal Readers group access (or a custom group with only read permissions)

Then reference both in your agent file:

permissions:
read: ado-aw-read
write: ado-aw-write
Configuration Agent can read ADO? Safe outputs can write?
Both read + write ✅ ✅ (configured connection identity)
Only read ✅ ✅ (default System.AccessToken)
Only write ❌ ✅ (configured connection identity)
Neither (default) ❌ ✅ (default System.AccessToken)

On the first run, Azure DevOps will prompt you to authorize the pipeline to use the service connections. You can also pre-authorize:

  1. In the service connection’s settings, go to Security
  2. Under Pipeline permissions, click + and add your ado-aw pipeline (or grant access to all pipelines in the project)

To confirm your service connection can mint ADO tokens, create a test pipeline:

trigger: none
pool:
vmImage: ubuntu-latest
steps:
- task: AzureCLI@3
displayName: "Test ADO token mint"
inputs:
connectionType: azureRM
azureSubscription: 'ado-aw-write' # your connection name
scriptType: 'bash'
scriptLocation: 'inlineScript'
inlineScript: |
TOKEN=$(az account get-access-token \
--resource 499b84ac-1321-427f-aa17-267ca6975798 \
--query accessToken -o tsv)
if [ -n "$TOKEN" ]; then
echo "✅ Successfully minted ADO token (${#TOKEN} chars)"
else
echo "❌ Failed to mint ADO token"
exit 1
fi

If this pipeline succeeds, your connection is correctly configured for ado-aw.


Symptom Likely cause
AzureCLI@3 fails with “service connection not found” The pipeline isn’t authorized to use the connection or connection-type does not match the server-side connection type
Token mints but safe outputs return 401/403 The service principal doesn’t have sufficient ADO permissions — verify its group membership in ADO Organization Settings → Users
“AADSTS700024: Client assertion is not within its valid time range” Federated credential issuer/subject mismatch — regenerate in the App Registration
Same-project safe-output writes return 403 with TF401027: ... 'PullRequestContribute' You’re on the default $(System.AccessToken) and the underlying build identity lacks PR-contribute (or has an explicit Deny) on the target repo. See the dedicated Safe-output 401/403 errors page for the diagnosis flow and three fix paths.
Cross-project safe-output writes fail with 403 even though default executor token usually works The pipeline setting “Limit job authorization scope to current project” is restricting $(System.AccessToken). Either disable it (broader scope) or set permissions.write to an ARM SC with explicit cross-project rights