Skip to content

Azure Repos: Automatically fall back to OAuth tokens when PAT creation is blocked by org policy #2344

Description

@iam-aniket

Problem:-

When an Azure DevOps organization has a policy that disables PAT creation (disablePatCreationPolicy), GCM fails with an error during
GeneratePersonalAccessTokenAsync() with no recovery path. The user must manually discover and set:

git config --global credential.azreposCredentialType oauth

This is a poor experience because:-

  • The error message doesn't suggest the workaround
  • The user has already successfully authenticated via AAD/Entra ID (the OAuth token was obtained), but the subsequent PAT creation step fails
  • The fix is simple - use the OAuth token directly - but users don't know this

Current Behaviour:-

  1. GCM detects Azure DevOps host
  2. UsePersonalAccessTokens() returns true (default on non-DevBox platforms)
  3. GeneratePersonalAccessTokenAsync() successfully obtains an AAD access token
  4. CreatePersonalAccessTokenAsync() calls _apis/token/sessiontokens → fails due to org policy
  5. Trace2Exception propagates to the user — no fallback, no helpful guidance

Expected Behavior:-

When PAT creation fails due to an organization policy block, GCM should:

  1. Detect the specific policy-block failure (via HTTP status code and/or error message)
  2. Log a warning: "PAT creation blocked by organization policy, falling back to OAuth tokens"
  3. Fall back to returning the OAuth/AAD access token directly (same path as credential.azreposCredentialType=oauth)

Environment

  • OS: macOS (but affects all non-DevBox platforms)
  • GCM version: latest
  • Azure DevOps org: Has disablePatCreationPolicy enabled
  • Auth method: az login via Entra ID

Proposed Fix:-

In AzureReposHostProvider.cs → GetCredentialAsync(), wrap the GeneratePersonalAccessTokenAsync() call in a try/catch that detects the policy-block error and falls
back to GetAzureAccessTokenAsync().

_

I'm happy to submit a PR for this. Before I do, could you confirm:

_

  1. What HTTP status code / error message does _apis/token/sessiontokens return when blocked by org policy? (I can capture this with GCM_TRACE=1 if needed)
  2. Is this the right approach, or would you prefer a different fallback strategy?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions