Skip to content

feat: Add Interactive Browser Credential as a fallback #307

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,10 +147,10 @@ For the best experience, use Visual Studio Code and GitHub Copilot.

1. Install [VS Code](https://code.visualstudio.com/download) or [VS Code Insiders](https://code.visualstudio.com/insiders)
2. Install [Node.js](https://nodejs.org/en/download) 20+
3. Install [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest)
3. Install [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) (Optional)
4. Open VS Code in an empty folder

### Azure Login
### Azure Login (If using Azure CLI)

Ensure you are logged in to Azure DevOps via the Azure CLI:

Expand Down Expand Up @@ -257,10 +257,10 @@ For the best experience, use Visual Studio Code and GitHub Copilot 👆.
### Prerequisites

1. Install [VS Studio 2022 version 17.14](https://learn.microsoft.com/en-us/visualstudio/releases/2022/release-history) or later
2. Install [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest)
2. Install [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) (Optional)
3. Open a project in Visual Studio.

### Azure Login
### Azure Login (If using Azure CLI)

Ensure you are logged in to Azure DevOps via the Azure CLI:

Expand Down
51 changes: 42 additions & 9 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import * as azdev from "azure-devops-node-api";
import { AccessToken, AzureCliCredential, ChainedTokenCredential, DefaultAzureCredential, TokenCredential } from "@azure/identity";
import { AccessToken, AzureCliCredential, DefaultAzureCredential, InteractiveBrowserCredential } from "@azure/identity";
import yargs from "yargs";
import { hideBin } from "yargs/helpers";

Expand Down Expand Up @@ -44,18 +44,51 @@ async function getAzureDevOpsToken(): Promise<AccessToken> {
} else {
process.env.AZURE_TOKEN_CREDENTIALS = "dev";
}
let credential: TokenCredential = new DefaultAzureCredential(); // CodeQL [SM05138] resolved by explicitly setting AZURE_TOKEN_CREDENTIALS

const scope = "499b84ac-1321-427f-aa17-267ca6975798/.default";
const errors: string[] = [];

// Try Azure CLI credential if tenantId is provided
if (tenantId) {
// Use Azure CLI credential if tenantId is provided for multi-tenant scenarios
const azureCliCredential = new AzureCliCredential({ tenantId });
credential = new ChainedTokenCredential(azureCliCredential, credential);
try {
const azureCliCredential = new AzureCliCredential({ tenantId });
const token = await azureCliCredential.getToken(scope);
if (token) {
return token;
}
} catch (error) {
errors.push(`AzureCliCredential failed: ${error}`);
}
}

// Try DefaultAzureCredential first (includes managed identity, environment variables, etc.)
try {
const defaultCredential = new DefaultAzureCredential(); // CodeQL [SM05138] resolved by explicitly setting AZURE_TOKEN_CREDENTIALS
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But this will bring back CodeQL warning?

Copy link
Author

@srathi-msft srathi-msft Jul 18, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @kboom,

The comment indicated that the fix for the warning is to explicitly set the environment variable AZURE_TOKEN_CREDENTIALS, which we are doing on lines 42-46.

I could not find any references on that particular warning [SM05138] on the internet, so not sure about its contents/reasons/fixes.

const token = await defaultCredential.getToken(scope);
if (token) {
return token;
}
} catch (error) {
errors.push(`DefaultAzureCredential failed: ${error}`);
}

const token = await credential.getToken("499b84ac-1321-427f-aa17-267ca6975798/.default");
if (!token) {
throw new Error("Failed to obtain Azure DevOps token. Ensure you have Azure CLI logged in or another token source setup correctly.");
// Try InteractiveBrowserCredential as final fallback
try {
const interactiveBrowserCredential = new InteractiveBrowserCredential({ tenantId });
const token = await interactiveBrowserCredential.getToken(scope, {
requestOptions: { timeout: 60000 }, // 1 minute timeout for interactive authentication
});
if (token) {
return token;
}
} catch (error) {
errors.push(`InteractiveBrowserCredential failed: ${error}`);
}
return token;

// If all credentials failed, throw an error with details
throw new Error(
`Failed to obtain Azure DevOps token. All authentication methods failed:\n${errors.join("\n")}\n\nTroubleshooting steps:\n1. Install Azure CLI and run 'az login'\n2. Set environment variables for service principal authentication\n3. Ensure you have access to Azure DevOps with the specified tenant`
);
}

function getAzureDevOpsClient(userAgentComposer: UserAgentComposer): () => Promise<azdev.WebApi> {
Expand Down