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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions