BrianM
BrianM

Reputation: 846

.Net Core - Use AzureAD Authentication to Access Azure DevOps REST APIs

I'm writing a Blazor web app to pull pipeline data from Azure DevOps. Up until now I've been using a PAT for the access, but I want users to be able to use their Azure AD account for the access instead of a PAT. I've added the Azure AD authentication via the Microsoft.AspNetCore.Authentication.AzureAD.UI library so that you have to log in with your Azure AD account to access the site, and that works.

Now that I have them logged in, I want to use that login for the VssConnection used to make the calls to the REST APIs. Currently I'm using a personal access token like this:

VssCredentials vssCredentials = new VssBasicCredential(string.Empty, PAT);
VssConnection vssConnection = new VssConnection(new Uri($"https://dev.azure.com/{Org}"), vssCredentials);

How do I change that to utilize the Azure AD login they are using so that they don't need to provide the PAT?

UPDATE

I think I'm really close on this. I found a library on Github called Microsoft.Identity.Web which appears to do what I want. I think I'm just struggling to understand how do make the calls with the right scopes. So in my startup I now have:

services.AddMicrosoftIdentityPlatformAuthentication(Configuration)
                .AddMsal(Configuration, scopes)
                .AddInMemoryTokenCaches();

where "scopes" is an array of strings. And later I have:

string token = await _tokenAcquisition.GetAccessTokenOnBehalfOfUserAsync(scopes);

where _tokenAcquisition is an ITokenAcquisition from Microsoft.Identity.Web. And again, scopes is an array of strings. I'm not sure what scopes I'm supposed to use for the two calls. In my application registration in Azure Portal, I have

Application Registration

So what scopes do I use for the call in Startup, and what do I use in the call later to get the token? I've tried so many options that I can't even mention them all. Some fail on the call in Startup. Some fail in the token acquisition. Some get all the way through and then tell me I can't access dev.azure.com. Any help would be GREATLY appreciated.

Upvotes: 3

Views: 6182

Answers (5)

Andrii Khavro
Andrii Khavro

Reputation: 11

This worked for me:

string token = await _tokenAcquisition.GetAccessTokenForUserAsync(new[] { "499b84ac-1321-427f-aa17-267ca6975798/.default" });
VssCredentials creds = new VssAadCredential(new VssAadToken("Bearer", token));

Here is the StackOverflow question which contains an answer with the correct scope: How to get valid AAD v2 token using MSAL.js for Azure DevOps

Upvotes: 1

Mohit Verma
Mohit Verma

Reputation: 5294

If you are looking to use client libraries to access azure devops rest api, you can check this repo like below:

//Prompt user for credential
VssConnection connection = new VssConnection(new Uri(azureDevOpsOrganizationUrl), new VssClientCredentials());

//create http client and query for resutls
WorkItemTrackingHttpClient witClient = connection.GetClient<WorkItemTrackingHttpClient>();
Wiql query = new Wiql() 
             { 
                Query = "SELECT [Id], [Title], [State] FROM workitems WHERE [Work Item Type] = 'Bug' AND [Assigned To] = @Me" 
             };
WorkItemQueryResult queryResults = witClient.QueryByWiqlAsync(query).Result;

//Display reults in console
if (queryResults == null || queryResults.WorkItems.Count() == 0)
{
    Console.WriteLine("Query did not find any results");
}
else
{
    foreach (var item in queryResults.WorkItems)
    {
        Console.WriteLine(item.Id);
    }
}

But most optimum way for fetching information For native applications which can support interactive authentication prompts is the Azure Active Directory Authentication Library (ADAL) makes it easy to setup authentication flows for users (Considering you are developing a web application which is AD authenticated).

Prerequisite:

  • A user account in your AAD tenant

  • A Azure DevOps account backed by your AAD tenant where your user account has access. If you have an existing Azure DevOps account not connected to your AAD tenant follow these steps to connect your AAD tenant to your Azure DevOps account

  • Register the sample application with you Azure Active Directory tenant (AAD backed Azure DevOps account). You can follow this doc to setup the application.

  • you can check below github sample for the elaborated sample: Sample

Check this for additional reference:

How to get user token silently for Azure DevOps and use it for accessing DevOps REST APIs?

Hope it helps.

Upvotes: 0

Fei Xue
Fei Xue

Reputation: 14649

Currently, Azure DevOps doesn't provide OAuth library for the Asp.net Core web app. You can refer the exits authentication samples from link below:

Choosing the right authentication mechanism

However we can implement OAuth 2.0 ourselves by following Authorize access to REST APIs with OAuth 2.0. You need to put a sign-in button on the web page and compose the authorization request by the apps you register for Azure DevOps, and handle the response and get the access token. After that you can use the token to call the Azure DevOps REST.

The OAuth for Azure DevOps is different with authentication using Azure AD, it is separate OAuth provide by Azure DevOps directly. Below is the different authorization and token url between Azure DevOps and Azure AD:

Azure DevOps(OAuth 2.0)

Authorize URL: https://app.vssps.visualstudio.com/oauth2/authorize

Access Token URL: https://app.vssps.visualstudio.com/oauth2/token

Azure AD(OAuth Code Grant flow)

Authorize URL: https://login.microsoftonline.com/{tenant}/oauth2/authorize

Access Token URL: https://login.microsoftonline.com/{tenant}/oauth2/token

I would suggest you vote and leave your feedback from oAuth for DevOps from Asp.Net Core app (3.0) if you like Microsoft provide the authentication library and code sample for Asp.net Core.

Upvotes: 1

Jeff West
Jeff West

Reputation: 1

Take a look at this Github repo...

https://github.com/Apollo3zehn/CryptoDrive

It is a Blazor Server-Side app that uses AAD for login and then calls Graph but it shows you how to get the auth code and then use that to get a token. The most relevant code is in Startup.cs and AzureAdAuthenticationBuilderExtensions.cs.

Just an FYI, that is not my repo or code. I just stumbled across trying to solve the same issue you have run into.

Upvotes: 0

Mengdi Liang
Mengdi Liang

Reputation: 18978

Have to log in with your Azure AD account to access the site.

If I did not have misunderstand, here it should pop up a dialog to allow users input their account info(username and password) and login in.

But, what the issue is, for our Azure Devops .Net Client library, its .NET Core version does not support the interactive sign-in prompt. Only .NET Framework version of the clients has this feature. But, unfortunately, what you are using is .net core.

Doc: sign-in prompt (Microsoft Account or Azure Active Directory backed) for REST services:

Because interactive dialogs are not supported by the .NET Core version of the clients, this sample applies only to the .NET Framework version of the clients.


Update:

 public class Program
     {
        // Do not change this id which fixed for azure devops.
        private const string VstsResourceId = "499b84ac-1321-427f-aa17-267ca6975798";
        public static void Main(string[] args)
        {
            var username = "{pass username here}"; 
            var password = "{pass password here}"; 
            var aadApplicationID = "{the application ID}"; 
            var adalCredential = new UserPasswordCredential(username, password);// make use of ADAL SDK
            var authenticationContext = new AuthenticationContext("https://login.microsoftonline.com/common");
            var result = authenticationContext.AcquireTokenAsync(VstsResourceId, aadApplicationID, adalCredential).Result;
            var token = new VssAadToken(result);
            var vstsCredential = new VssAadCredential(token);
            var connection = new VssConnection(new Uri("https://dev.azure.com/{org name}"), vstsCredential);
            var client = connection.GetClient<DelegatedAuthorizationHttpClient>();
            var pat = client.CreateSessionToken(
                displayName: "PAT Generate",
                tokenType: SessionTokenType.Compact,
                scope: "vso.work"
                ).Result;
           //print the token to verify the script
            Console.WriteLine(pat.Token);
        }
    }

For application id, please go check this doc to finish the register. .

Upvotes: 0

Related Questions