Use SSH for Git Authentication in Azure DevOps

If you work with Azure DevOps Git repos, SSH is often the simplest, most secure, and most policy‑friendly way to authenticate. Many organizations disable Personal Access Tokens (PATs) for security reasons, which breaks HTTPS cloning and pushes. If you’ve seen this error when using HTTPS, you’ve run into such a policy:

1fatal: Failed to create PAT: DisablePatCreationPolicyViolation

In this guide you’ll switch to SSH, generate a modern key, register it with Azure DevOps, convert your remotes, and fix the common “password prompt” pitfalls. Clear, copy‑pasteable steps are included for Windows, macOS, and Linux.

Why SSH instead of HTTPS/PAT?

  • Security: SSH keys are asymmetric, can be protected with a passphrase, and don’t get exfiltrated in the same way static tokens do.
  • Compliance: Many orgs disable PAT creation. SSH continues to work.
  • Developer ergonomics: Once your agent is set up, pushing/pulling is seamless across repos.

What that PAT error means

When you use an HTTPS remote with Git Credential Manager (GCM), it tries to create a PAT behind the scenes. If the org policy forbids PATs, you get:

1fatal: Failed to create PAT: DisablePatCreationPolicyViolation

The fix is to use SSH remotes instead of HTTPS.

Prerequisites

  • OpenSSH client available (Windows 10/11, macOS, and most Linux distributions include it).
  • Your Azure DevOps account and access to the target org/project.

Step 1 — Generate an SSH key

Azure DevOps supports RSA SSH keys. Generate an RSA key (4096‑bit). OpenSSH uses SHA‑2 signatures (rsa‑sha2‑512/256) by default, which Azure DevOps requires.

1# Create the .ssh folder if missing
2New-Item -ItemType Directory -Force $HOME/.ssh | Out-Null
3
4# Generate an RSA key (4096-bit, modern key format, with key stretching)
5ssh-keygen -t rsa -b 4096 - $(whoami)" -f "$HOME/.ssh/id_rsa"

Notes:

  • You can choose a different filename (e.g., ~/.ssh/ado_id_rsa). If you do, add an SSH config entry in Step 3.
  • A passphrase is strongly recommended; it protects the private key at rest.
1# Start the built-in OpenSSH agent (service persists across sessions)
2Get-Service ssh-agent -ErrorAction SilentlyContinue | Start-Service
3
4# Add your key to the agent
5ssh-add "$HOME/.ssh/id_rsa"

Tip: If you used a custom filename, point ssh-add to that file instead.

Step 3 — (Recommended) Create an SSH config entry

This tells SSH which key to use for Azure DevOps and avoids the dreaded password prompt when the wrong key is tried.

Create or edit ~/.ssh/config:

1Host ssh.dev.azure.com
2  HostName ssh.dev.azure.com
3  User git
4  IdentityFile ~/.ssh/id_rsa
5  IdentitiesOnly yes

If you use multiple keys (for different orgs or services), add more entries and use aliases:

 1Host ado-work
 2  HostName ssh.dev.azure.com
 3  User git
 4  IdentityFile ~/.ssh/ado_work_rsa
 5  IdentitiesOnly yes
 6
 7Host ado-private
 8  HostName ssh.dev.azure.com
 9  User git
10  IdentityFile ~/.ssh/ado_private_rsa
11  IdentitiesOnly yes

You can then use the alias in remotes: git@ado-work:v3/ORG/PROJECT/REPO.

Step 4 — Add the public key in Azure DevOps

  1. Copy your public key to the clipboard:
1Get-Content "$HOME/.ssh/id_rsa.pub" | Set-Clipboard
  1. In Azure DevOps (web):
  • Top right: User settings (your avatar) → SSH Public Keys → Add
  • Paste the key and give it a meaningful name
  • Save

Step 5 — Switch your Git remotes to SSH

Azure DevOps SSH URL format:

1git@ssh.dev.azure.com:v3/ORG/PROJECT/REPO

Convert an existing remote named origin:

1git remote set-url origin git@ssh.dev.azure.com:v3/ORG/PROJECT/REPO

Or clone fresh via SSH:

1git clone git@ssh.dev.azure.com:v3/ORG/PROJECT/REPO

Test the connection explicitly:

1ssh -T git@ssh.dev.azure.com

You should see a success/authenticated message.

Troubleshooting

Password prompt

1Cloning into 'REPO'...
2git@ssh.dev.azure.com's password:

This indicates SSH didn’t offer a valid key. Common causes and fixes:

  • Key not loaded in agent: run ssh-add -l to list keys; if empty, add it with ssh-add ~/.ssh/id_rsa.
  • Custom filename but no SSH config: add a Host ssh.dev.azure.com entry with IdentityFile and IdentitiesOnly yes.
  • Wrong remote URL: ensure it starts with git@ssh.dev.azure.com:v3/... (not HTTPS).
  • Permissions (mostly Linux/macOS): chmod 700 ~/.ssh && chmod 600 ~/.ssh/*.
  • Multiple keys collide: use per-host aliases (Host ado-work) and point to the right IdentityFile.

“DisablePatCreationPolicyViolation” (with HTTPS)

You’re on an HTTPS remote using Git Credential Manager, which tries to create a PAT and is blocked by org policy. Switch to SSH (this guide) or ask your admin about allowed auth methods.

Windows-specific tips

  • Ensure the Windows OpenSSH agent service is running and set to Automatic start if you want persistence.
  • If you store keys in a non-default location, an SSH config is the most reliable way to avoid prompts.

Best practices

  • Use RSA 4096‑bit keys for Azure DevOps (OpenSSH defaults to SHA‑2 signatures).
  • Protect private keys with a passphrase; let the agent cache the key during your session.
  • Use separate keys per machine and/or per trust boundary (work vs. personal).
  • Rotate keys periodically (remove old keys from Azure DevOps when decommissioned).
  • Never commit or share private keys; back them up securely if needed.

FAQ

Do keys have to be named id_rsa?

  • No. That’s just a default. You can pick any filename; if not default, map it via ~/.ssh/config or pass it to ssh-add.

Can I keep using HTTPS?

  • If your org disables PATs, HTTPS with Git Credential Manager won’t work for pushes. SSH is the robust alternative.

Can I use one key across multiple orgs?

  • Yes. One key per user is fine. Some teams prefer separate keys per machine/org; both approaches are viable if managed well.

Wrap up

You’ve switched your Azure DevOps Git auth to SSH: modern key, agent configured, key registered, remotes updated. No more PAT policy errors, and no more password prompts once the agent has your key. If you run into an issue, start with ssh -T git@ssh.dev.azure.com and verify your key is loaded and mapped in ~/.ssh/config.


Comments

Twitter Facebook LinkedIn WhatsApp