Skip to main content
Glama
auth.ts3.37 kB
// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. import { AzureCliCredential, ChainedTokenCredential, DefaultAzureCredential, TokenCredential } from "@azure/identity"; import { AccountInfo, AuthenticationResult, PublicClientApplication } from "@azure/msal-node"; import open from "open"; const scopes = ["499b84ac-1321-427f-aa17-267ca6975798/.default"]; class OAuthAuthenticator { static clientId = "0d50963b-7bb9-4fe7-94c7-a99af00b5136"; static defaultAuthority = "https://login.microsoftonline.com/common"; static zeroTenantId = "00000000-0000-0000-0000-000000000000"; private accountId: AccountInfo | null; private publicClientApp: PublicClientApplication; constructor(tenantId?: string) { this.accountId = null; let authority = OAuthAuthenticator.defaultAuthority; if (tenantId && tenantId !== OAuthAuthenticator.zeroTenantId) { authority = `https://login.microsoftonline.com/${tenantId}`; } this.publicClientApp = new PublicClientApplication({ auth: { clientId: OAuthAuthenticator.clientId, authority, }, }); } public async getToken(): Promise<string> { let authResult: AuthenticationResult | null = null; if (this.accountId) { try { authResult = await this.publicClientApp.acquireTokenSilent({ scopes, account: this.accountId, }); } catch (error) { authResult = null; } } if (!authResult) { authResult = await this.publicClientApp.acquireTokenInteractive({ scopes, openBrowser: async (url) => { open(url); }, }); this.accountId = authResult.account; } if (!authResult.accessToken) { throw new Error("Failed to obtain Azure DevOps OAuth token."); } return authResult.accessToken; } } function createAuthenticator(type: string, tenantId?: string): () => Promise<string> { switch (type) { case "pat": // Use Personal Access Token from environment variable return async () => { const token = process.env.AZURE_DEVOPS_PAT || process.env.ADO_PAT; if (!token) { throw new Error( "Personal Access Token not found. Please set AZURE_DEVOPS_PAT or ADO_PAT environment variable." ); } return token; }; case "azcli": case "env": if (type !== "env") { process.env.AZURE_TOKEN_CREDENTIALS = "dev"; } let credential: TokenCredential = new DefaultAzureCredential(); // CodeQL [SM05138] resolved by explicitly setting AZURE_TOKEN_CREDENTIALS if (tenantId) { // Use Azure CLI credential if tenantId is provided for multi-tenant scenarios const azureCliCredential = new AzureCliCredential({ tenantId }); credential = new ChainedTokenCredential(azureCliCredential, credential); } return async () => { const result = await credential.getToken(scopes); if (!result) { throw new Error("Failed to obtain Azure DevOps token. Ensure you have Azure CLI logged or use interactive type of authentication."); } return result.token; }; default: const authenticator = new OAuthAuthenticator(tenantId); return () => { return authenticator.getToken(); }; } } export { createAuthenticator };

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/magemaclean/azure-devops-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server