Skip to content

Available Options

There are multiple authentication methods available. The first fork in the decision tree is whether you have the Observes extension installed.

  • Observes Scanner - Extension Installed
  • Standalone Scanner - Extension Not Installed

For a deep dive on configuring Managed Identity or Workload Identity Federation, follow this guide.


Observes Scanner - Extension Installed

The Observes task supports two service connection types, selected via the --auth-mode input. Each supports multiple credential kinds.

  • Option 1: Observes Service Connection
  • Option 2: ARM Service Connection

Option 1: Observes Service Connection

An Observes service connection is created under Project Settings > Service connections > New service connection > Observes Azure DevOps Scanner. It supports three credential kinds:

1a. PAT (Personal Access Token)

Best for quick setup. Least recommended for production due to manual token rotation.

Create the service connection:

  1. Go to Project Settings > Service connections > New service connection > Observes Azure DevOps Scanner
  2. Select Basic Authentication as the Authentication method
  3. Enter the PAT token in the input field
  4. Name the Service Connection and save (for example: service-connection-observes-pat)

Pipeline:

- task: observes@1
  displayName: 'Observes Security Scan'
  inputs:
    authMethod: observes
    observesServiceConnection: 'service-connection-observes-pat'
    organization: 'my-ado-org'

1b. Service Principal - Client Secret

Create the service connection:

  1. Go to Project Settings > Service connections > New service connection > Observes Azure DevOps Scanner
  2. Select Token Based Authentication as the Authentication method
  3. Enter your Tenant ID, Client ID, and Client Secret
  4. Name the Service Connection and save (for example: service-connection-observes-app-reg-secret)

Pipeline:

- task: observes@1
  displayName: 'Observes Security Scan'
  inputs:
    authMethod: observes
    observesServiceConnection: 'service-connection-observes-app-reg-secret'
    organization: 'my-ado-org'

1c. Service Principal - Certificate

Create the service connection:

  1. Go to Project Settings > Service connections > New service connection > Observes Azure DevOps Scanner
  2. Select Certificate Based as the Authentication method
  3. Enter your Tenant ID, Client ID, and upload the PEM certificate
  4. Name the Service Connection and save (for example: service-connection-observes-app-reg-cert)

Pipeline:

- task: observes@1
  displayName: 'Observes Security Scan'
  inputs:
    authMethod: observes
    observesServiceConnection: 'service-connection-observes-app-reg-cert'
    organization: 'my-ado-org'

Option 2: ARM Service Connection

Uses a standard Azure Resource Manager service connection. If you already have an ARM service connection configured in your project, you can point the Observes task directly at it. Because an ARM connection does not embed an Azure DevOps organization name, the organization field is always required when using this method.

The task automatically maps the ARM connection's credential kind to the correct scanner auth mode:

Head over to this guide for more information about managed identity set ups.

Create the service connection:

  1. Go to Project Settings > Service connections > New service connection > Azure Resource Manager
  2. Select Workload Identity Federation (automatic) - ADO creates and configures the app registration for you
  3. Select your subscription and optionally scope to a resource group
  4. Name the Service Connection and save (for example: service-connection-arm-app-reg-wif)

Pipeline:

- task: observes@1
  displayName: 'Observes Security Scan'
  inputs:
    authMethod: arm
    armServiceConnection: 'service-connection-arm-app-reg-wif'
    organization: 'my-ado-org'

Note: System-Assigned Managed Identity connections only work on self-hosted agents running on Azure compute with a managed identity attached. For Microsoft-hosted runners, use Workload Identity Federation / User-Assigned Managed Identities attached to the pipeline instead.

2b. Service Principal - Client Secret

Create the service connection:

  1. Go to Project Settings > Service connections > New service connection > Azure Resource Manager
  2. Select Service Principal (manual)
  3. Enter your Tenant ID, Subscription ID, Client ID, and Client Secret
  4. Name the Service Connection and save (for example: service-connection-arm-app-reg-secret)

Pipeline:

- task: observes@1
  displayName: 'Observes Security Scan'
  inputs:
    authMethod: arm
    armServiceConnection: 'service-connection-arm-app-reg-secret'
    organization: 'my-ado-org'

2c. Service Principal - Certificate

Create the service connection: 1. Go to Project Settings > Service connections > New service connection > Azure Resource Manager 2. Select Service Principal (manual) 3. Enter your Tenant ID, Subscription ID, Client ID, and upload the certificate 4. Name the Service Connection and save (for example: service-connection-arm-app-reg-cert)

Pipeline:

- task: observes@1
  displayName: 'Observes Security Scan'
  inputs:
    authMethod: arm
    armServiceConnection: 'service-connection-arm-app-reg-cert'
    organization: 'my-ado-org'

Standalone Scanner - Extension Not Installed

When running the scanner without the Observes extension, you can leverage the command line options to use the authentication method that best suits you:

Mode Flag Description
Default --auth-mode default Auto-detects credentials via DefaultAzureCredential. Tries env vars, workload identity, managed identity, and Azure CLI session in order. Best for pipelines using AzureCLI@3 with a service connection.
PAT --auth-mode pat -p <TOKEN> Personal Access Token (Basic auth). PAT can also be set via AZURE_DEVOPS_PAT env var. Best for local/quick testing.
Service Principal --auth-mode service-principal Microsoft Entra app registration. Requires --tenant-id, --client-id, and one of --client-secret or --client-certificate-path.
Managed Identity --auth-mode managed-identity Azure-managed identity. Requires running on Azure compute. Requires --client-id if using user-assigned identities.

Default (AzureCLI@3 with service connection)

The recommended approach for most pipelines. ADO injects credentials automatically via the service connection — no secrets to manage in the pipeline itself.

- task: AzureCLI@3
  displayName: 'Observes Security Scan'
  inputs:
    azureSubscription: 'service-connection-arm-app-reg-wif'
    scriptType: bash
    scriptLocation: inlineScript
    inlineScript: |
      python scan.py -o my-ado-org -j my_scan

PAT (Personal Access Token)

Store the PAT as a secret in a key vault, variable group, secure file or your agreed secret storage pattern. Then make it available to the script either by using environment variables or directly in the command line script.

# Using environment variables
- script: |
    python scan.py -o my-ado-org -j my_scan --auth-mode pat
  displayName: 'Observes Security Scan'
  env:
    AZURE_DEVOPS_PAT: $(OBSERVES_PAT)
# OR - Using the command line flag
- script: |
    python scan.py -o my-ado-org -j my_scan --auth-mode pat -p $(OBSERVES_PAT)
  displayName: 'Observes Security Scan'

Your secret may be exposed in the logs when using the command-line flag, hence it is not recommended.


Service Principal - Client Secret

Store AZURE_CLIENT_SECRET as a secret in a key vault, variable group, secure file or your agreed secret storage pattern. Then make it available to the script either by using environment variables or directly in the command line script.

# Using environment variables

- script: |
    python scan.py -o my-ado-org -j my_scan \
      --auth-mode service-principal \
      --tenant-id $(AZURE_TENANT_ID) \
      --client-id $(AZURE_CLIENT_ID)
  displayName: 'Standalone - SP Secret'
  env:
    AZURE_CLIENT_SECRET: $(AZURE_CLIENT_SECRET)

# OR - Using the command line flag

- script: |
    python scan.py -o my-ado-org -j my_scan \
      --auth-mode service-principal \
      --tenant-id $(AZURE_TENANT_ID) \
      --client-id $(AZURE_CLIENT_ID) \
      --client-secret $(AZURE_CLIENT_SECRET)
  displayName: 'Observes Security Scan'

Your secret may be exposed in the logs when using the command-line flag, hence it is not recommended.


Service Principal - Certificate

The certificate file must be available on the agent at run time. Store it somewhere safe, like in a key vault and when running in the pipeline, download it to an accessible place.

- script: |
    python scan.py -o my-ado-org -j my_scan \
      --auth-mode service-principal \
      --tenant-id $(AZURE_TENANT_ID) \
      --client-id $(AZURE_CLIENT_ID) \
      --client-certificate-path /path/to/certificate.pem
  displayName: 'Observes Security Scan'

Managed Identity

Requires a self-hosted agent running on Azure compute with a managed identity attached.

  • For system-assigned identities, omit --client-id.
  • For user-assigned identities, provide --client-id explicitly. This is because a single workload may have multiple user-assigned identities, and you need to specify which one you want to use in the scan.
# System-assigned managed identity
- script: |
    python scan.py -o my-ado-org -j my_scan --auth-mode managed-identity
  displayName: 'Observes Security Scan'
# User-assigned managed identity
- script: |
    python scan.py -o my-ado-org -j my_scan \
      --auth-mode managed-identity \
      --client-id $(AZURE_CLIENT_ID)
  displayName: 'Observes Security Scan'

Default Behaviour

When you run python scan.py -o my_org -j my_scan without specifying --auth-mode, the scanner automatically tries to authenticate using DefaultAzureCredential, which checks the following sources in order:

  1. Environment variables (AZURE_TENANT_ID + AZURE_CLIENT_ID + AZURE_CLIENT_SECRET / AZURE_CLIENT_CERTIFICATE_PATH)
  2. Workload identity (example: AKS workload identity webhook)
  3. Managed identity (system- or user-assigned, when running on Azure compute)
  4. Azure CLI session (when running inside an AzureCLI@3 pipeline task or after az login locally)

Full Example - All methods in one pipeline

trigger: none

pool:
  vmImage: ubuntu-latest

jobs:
  # Extension - ARM - Workload Identity Federation
  - job: RunObservesArmWif
    steps:
      - task: observes@1
        displayName: 'ARM - WIF'
        inputs:
          authMethod: arm
          armServiceConnection: 'service-connection-arm-app-reg-wif'
          organization: 'my-ado-org'

  # Extension - ARM - Service Principal (secret)
  - job: RunObservesArmSecret
    steps:
      - task: observes@1
        displayName: 'ARM - SP Secret'
        inputs:
          authMethod: arm
          armServiceConnection: 'service-connection-arm-app-reg-secret'
          organization: 'my-ado-org'

  # Extension - ARM - Service Principal (certificate)
  - job: RunObservesArmCert
    steps:
      - task: observes@1
        displayName: 'ARM - SP Certificate'
        inputs:
          authMethod: arm
          armServiceConnection: 'service-connection-arm-app-reg-cert'
          organization: 'my-ado-org'

  # Extension - Observes - PAT
  - job: RunObservesObsPat
    steps:
      - task: observes@1
        displayName: 'Observes - PAT'
        inputs:
          authMethod: observes
          observesServiceConnection: 'service-connection-observes-pat'
          organization: 'my-ado-org'

  # Extension - Observes - Service Principal (secret)
  - job: RunObservesObsSecret
    steps:
      - task: observes@1
        displayName: 'Observes - SP Secret'
        inputs:
          authMethod: observes
          observesServiceConnection: 'service-connection-observes-app-reg-secret'
          organization: 'my-ado-org'

  # Extension - Observes - Service Principal (certificate)
  - job: RunObservesObsCert
    steps:
      - task: observes@1
        displayName: 'Observes - SP Certificate'
        inputs:
          authMethod: observes
          observesServiceConnection: 'service-connection-observes-app-reg-cert'
          organization: 'my-ado-org'

  # Standalone - Default (AzureCLI@3 with WIF service connection)
  - job: RunStandaloneDefault
    steps:
      - task: AzureCLI@3
        displayName: 'Standalone - Default (AzureCLI WIF)'
        inputs:
          azureSubscription: 'service-connection-arm-app-reg-wif'
          scriptType: bash
          scriptLocation: inlineScript
          inlineScript: |
            python scan.py -o my-ado-org -j my_scan

  # Standalone - PAT
  - job: RunStandalonePat
    steps:
      - script: |
          python scan.py -o my-ado-org -j my_scan --auth-mode pat
        displayName: 'Standalone - PAT'
        env:
          AZURE_DEVOPS_PAT: $(OBSERVES_PAT)

  # Standalone - Service Principal (secret)
  - job: RunStandaloneSpSecret
    steps:
      - script: |
          python scan.py -o my-ado-org -j my_scan \
            --auth-mode service-principal \
            --tenant-id $(AZURE_TENANT_ID) \
            --client-id $(AZURE_CLIENT_ID)
        displayName: 'Standalone - SP Secret'
        env:
          AZURE_CLIENT_SECRET: $(AZURE_CLIENT_SECRET)

  # Standalone - Service Principal (certificate)
  - job: RunStandaloneSpCert
    steps:
      - script: |
          python scan.py -o my-ado-org -j my_scan \
            --auth-mode service-principal \
            --tenant-id $(AZURE_TENANT_ID) \
            --client-id $(AZURE_CLIENT_ID) \
            --client-certificate-path /path/to/certificate.pem
        displayName: 'Standalone - SP Certificate'

  # Standalone - Managed Identity (system-assigned)
  - job: RunStandaloneMiSystem
    pool:
      name: my-self-hosted-pool  # must run on Azure compute with managed identity attached
    steps:
      - script: |
          python scan.py -o my-ado-org -j my_scan --auth-mode managed-identity
        displayName: 'Standalone - Managed Identity (system-assigned)'

  # Standalone - Managed Identity (user-assigned)
  - job: RunStandaloneMiUser
    pool:
      name: my-self-hosted-pool  # must run on Azure compute with managed identity attached
    steps:
      - script: |
          python scan.py -o my-ado-org -j my_scan \
            --auth-mode managed-identity \
            --client-id $(AZURE_CLIENT_ID)
        displayName: 'Standalone - Managed Identity (user-assigned)'

Final remarks / FAQ

  • Service principal and managed identity auth require pip install azure-identity.
  • No explicit credentials are needed when running inside an AzureCLI@3 pipeline task with a service connection - the scanner picks up the active session automatically.
  • If using --auth-mode pat and no PAT token is provided (-p ), the tool will exit with an error. For PAT authentication (--auth-mode pat), also specify the PAT token.
  • As a CLI argument: -p or --pat-token
  • As an environment variable: AZURE_DEVOPS_PAT
  • If you have installed the Observes extension, the observes pipeline task handles authentication automatically - you do not need to pass --auth-mode or any credential flags manually.