How to authenticate to Azure DevOps PATs API?

Federico Crovetto 20 Reputation points
2025-01-28T18:43:04.7933333+00:00

I'm creating an Azure Function in Node.js which needs to list, create and delete Azure DevOps PAT's, but as the title says, I'm having troubles with authentication / authorization.

I've read the wiki (https://learn.microsoft.com/en-us/rest/api/azure/devops/tokens/?view=azure-devops-rest-7.2) and it states that I can't use a PAT for this, and that I must use an Azure AD Access Token.

Created the app on Microsoft Entra Id, then a client secret, and then assigned the API Permissions vso.tokenadministration and vso.tokens on Azure DevOps App.

I'm using MSAL library to retrieve an authorization code in my Function App. It's working perfectly and it's returning a valid auth code.

const config = {
    auth: {
      clientId: process.env.AZURE_CLIENT_ID,
      authority: "https://login.microsoftonline.com/" + process.env.AZURE_TENANT_ID, 
      clientSecret: process.env.AZURE_CLIENT_SECRET,
    }
};
const cca = new ConfidentialClientApplication(config);
const result = await cca.acquireTokenByClientCredential({
      scopes: ["499b84ac-1321-427f-aa17-267ca6975798/.default"], 
});  
        
return result.accessToken;

The thing is this code is not authorized to interact with the PATs API.

At first I got the following error:

Access Denied: 00000000-0000-0000-0000-000000000000 needs the following permission(s) on the resource Subjects to perform this action: Read by public identifier

Then, after trying some solutions managed to get the following (to be honest, don't know which user is referring to)

The user '92ec58a6-8a14-6563-a4b4-d1d0e40f40ff' is not authorized to access this resource.

Things I've tried:

  • Tried messing around with API Permissions, but could not find the right one.
  • Tried adding my app into an Azure DevOps Group but got another error saying server principals are not allowed to this action.
  • Tried using a PAT anyway (of course, it didn't work)
  • Tried retrieving the token using ROPC Flow to obtain an access token and a non-interactive user, use delegated permissions, but we have multi-factor enabled so it won't work either.

I don't really know what else to do. Does anybody have any help?

Microsoft Entra ID
Microsoft Entra ID
A Microsoft Entra identity service that provides identity management and access control capabilities. Replaces Azure Active Directory.
23,148 questions
0 comments No comments
{count} votes

1 answer

Sort by: Most helpful
  1. Sanoop M 600 Reputation points Microsoft Vendor
    2025-01-30T23:21:19.5866667+00:00

    Hello @Federico Crovetto,

    Thank you for posting your query on Microsoft Q&A.

    Firstly please note that, Service Principal authentication is not supported to work with Azure DevOps PATs API. You can only use delegated flows that involves user interaction to make it work.

    As your requirement is to avoid user interactions, the only way is to make use of ROPC flow. But if MFA is enabled for the user, you cannot use ROPC flow to generate the access token.

    To resolve this, please make sure to disable the MFA for the user and generate access token using username password (ROPC) flow.

    Important:

    • The Microsoft identity platform only supports the ROPC grant within Microsoft Entra tenants, not personal accounts. This means that you must use a tenant-specific endpoint (https://login.microsoftonline.com/{TenantId_or_Name}) or the organizations endpoint.
    • Accounts that don't have passwords can't sign in with ROPC, which means features like SMS sign-in, FIDO, and the Authenticator app won't work with that flow. If your app or users require these features, use a grant type other than ROPC.
    • If users need to use multi-factor authentication (MFA) to log in to the application, they will be blocked instead.

    For additional details, please refer to the below document.

    https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth-ropc

    Please try to add the API permissions as mentioned in the below Screenshot.

    enter image description here I ran below code files and got the response successfully like this:

    auth.js:

    require("dotenv").config();

    const { PublicClientApplication } = require("@azure/msal-node");

     

    async function getAccessToken() {

        const config = {

            auth: {

                clientId: process.env.AZURE_CLIENT_ID,

                authority: https://login.microsoftonline.com/${process.env.AZURE_TENANT_ID},

            }

        };

     

        const pca = new PublicClientApplication(config);

     

        try {

            const authResponse = await pca.acquireTokenByUsernamePassword({

                scopes: ["499b84ac-1321-427f-aa17-267ca6975798/.default"],

                username: process.env.AZURE_USERNAME,  // Your username (email)

                password: process.env.AZURE_PASSWORD,  // Your password

            });

     

            console.log("Access Token:", authResponse.accessToken);

            return authResponse.accessToken;

        } catch (error) {

            console.error("Error acquiring access token:", error);

        }

    }

     

    if (require.main === module) {

        getAccessToken();

    }

     

    module.exports = getAccessToken;

     

    fetchPats.js:

    require("dotenv").config();

    const axios = require("axios");

    const getAccessToken = require("./auth");

     

    async function fetchPats() {

        try {

            const accessToken = await getAccessToken();

            if (!accessToken) throw new Error("Failed to acquire access token");

     

            const url = "https://vssps.dev.azure.com/sridevOps22/_apis/tokens/pats?api-version=7.1-preview.1";

     

            const response = await axios.get(url, {

                headers: {

                    "Authorization": Bearer ${accessToken},

                    "Content-Type": "application/json",

                }

            });

     

            console.log("\nPAT Tokens Response:", JSON.stringify(response.data, null, 2));

        } catch (error) {

            console.error("Error fetching PAT tokens:", error.response?.data || error.message);

        }

    }

     

    fetchPats();

    Response:

    enter image description here

    I hope this above information provided is helpful. Please feel free to reach out if you have any further questions.

    If the answer is helpful, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

    Thanks and Regards,

    Sanoop Mohan


Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.