Azure DevOps: Update service connection expired secret

If you’re reading this post, you’re trying to find a way to edit an existing service connection with a new service principal secret/key.

It’s a weird that UI and devops cli don’t allow us to quickly change service connection details if it was created automatically by Azure DevOps (“creationMode”: “Automatic”; will talk about it a bit later).

So, how to change a secret? Answer: Azure DevOps REST API.
Note: if you have correct permissions, try out the steps at the bottom of the post. The steps below are for those who don’t have Owner permissions.

  • Create a new Personal Access Token (full access and all scope, expiration 1 day)
  • Go to Project Settings – Service Connections, choose your connection and click on Manage Service Principal. Add a new secret and note it’s value.
  • Choose a tool to work with REST API. It could be either PowerShell or Postman, for instance. I will show both.
  • [Postman] Install Postman and create a new HTTP Request
Postman – File – New – HTTP Request
  • [Postman] Go to Authorization and paste PAT token to the password field
PAT token should be used as password for any REST API requests
  • [Postman] Using the following GET request, get a service endpoint details in JSON format. Organization Name, Project Name and Endpoint Name are parts of the URI (can be taken from service connections list in the azure devops ui) :<orgName>/<ProjectName>/_apis/serviceendpoint/endpoints?endpointNames=<Endpoint Name> &api-version=6.0-preview.4
  • [Postman] Copy everything from the response under the value as shown below
            "data": {
                "subscriptionId": "",
                "subscriptionName": "",
                "environment": "AzureCloud",
                "scopeLevel": "Subscription",
                "creationMode": "Automatic",
                "azureSpnRoleAssignmentId": ""
  • [Postman] Using a PUT request update the service connection. Make sure you set Body – Raw to JSON , and then Paste JSON copied in the previous step to the Body
Body – RAW should be set to JSON
  • Here is a tricky part. Prior to sending PUT request, change creationMode from “Automatic” to “Manual”. Also, in my case, I had to delete the following parameters spnObjectId and appObjectId (data section). Plus, I added serviceprincipalkey with a value set to a new secret (authorization section)
    A short excerpt is provided below:
    "data": {
        "subscriptionId": "",
        "subscriptionName": "",
        "environment": "AzureCloud",
        "scopeLevel": "Subscription",
        "creationMode": "Manual",  # changed
        "azureSpnRoleAssignmentId": "",
        "azureSpnPermissions": ""
         spnObjectId # deleted
         appObjectId # deleted
    "description": "",
    "authorization": {
        "parameters": {
            "tenantid": "",
            "serviceprincipalid": "",
            "authenticationType": "spnKey",
            "serviceprincipalkey": "secret here" # added
        "scheme": "ServicePrincipal"
  • [Postman] URI used for a PUT request:
  • [Postman] Go back to Azure DevOps and make sure that service connections has been updated and ready to use.

  • [PowerShell] Use the following example
$token ="PAT Token"
$orgName = "Organization Name"
$projectName = "Project Name"
$endpointName = "your endpoint"
$endpointId = "your endpoint ID, use GET request or UI"
$header = @{Authorization = 'Basic ' + [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(":$($token)")) }

# Get Endpoint details

Invoke-RestMethod -Method GET -URI "$($orgName)/$($projectName)/_apis/serviceendpoint/endpoints?endpointNames=$($endpointName)&api-version=6.0-preview.4" -Headers $header -ContentType "application\json"

# Update Endpoint
$json = @{ json here } | ConvertTo-Json -Depth <your depth>
Invoke-RestMethod -Method PUT -URI "$($OrgName)/_apis/serviceendpoint/endpoints/$($endpointId)?api-version=6.0-preview.4" -Body -Headers $header -ContentType "application\json" -Body $json

That’s it. Now you know how to change a service connection with a new secret without removing a connection and customizing all pipelines in a project.

P.S. If you have Owners permissions on the app registration/service principal used by the connection, try to edit the connection by adding a description, and then click on Save. Azure DevOps should create a new secret and update the connection automatically.

How to stop Azure Application Gateway

I often makes demo setups in my Azure subscription that has spending limits, so I have to gracefully shutdown all “hungry” resources to save some money such as VMs , Application Gateways and etc. To stop VMs, you can simply use the Azure Portal start/stop buttons, however, Azure Portal doesn’t allow you to stop application gateway. In such cases, Azure PowerShell helps.

Open the Azure Cloud Shell or local PowerShell with Az module installed and use the following:

# Get Azure Application Gateway
$appgw=Get-AzApplicationGateway -Name <appgw_name> -ResourceGroupName <rg_name>

# Stop the Azure Application Gateway
Stop-AzApplicationGateway -ApplicationGateway $appgw

# Start the Azure Application Gateway (optional)
Start-AzApplicationGateway -ApplicationGateway $appgw

Azure Portal updates the Application Gateway:

Azure Portal - Application Gateway Stopping

Verify the application gateway has stopped state. You will only billed for the public IP assigned to the stopped Application Gateway (saves money significantly):

Azure Portal - Stopped Azure Application Gateway

Start the application gateway (optional):

Azure Portal - Application Gateway Running State
%d bloggers like this: