Skip to content
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

Azure.Identity.InteractiveBrowserCredential Fails #17696

Closed
luckerby opened this issue Dec 23, 2020 · 3 comments
Closed

Azure.Identity.InteractiveBrowserCredential Fails #17696

luckerby opened this issue Dec 23, 2020 · 3 comments
Assignees
Labels
Azure.Identity Client This issue points to a problem in the data-plane of the library. customer-reported Issues that are reported by GitHub users external to the Azure organization. needs-team-attention This issue needs attention from Azure service team or SDK team question The issue doesn't require a change to the product in order to be resolved. Most issues start as that

Comments

@luckerby
Copy link

luckerby commented Dec 23, 2020

I'm working on running some queries using Azure Resource Graph with C#. In the process, I'm trying to get a token interactively using the following code:

InteractiveBrowserCredential credential = new InteractiveBrowserCredential();
Azure.Core.AccessToken authToken = credential.GetToken(new Azure.Core.TokenRequestContext(new string[] { "https://management.core.windows.net/scope" }));

When the code runs, a browser does open and I can successfully authenticate. However, once done, I run into the following error:

Authentication failed. You can return to the application. Feel free to close this browser tab.

Error details: error invalid_request error_description: AADSTS65002: Consent between first party application '04b07795-8ddb-461a-bbee-02f9e1bf7b46' and first party resource '797f4846-ba00-4fd7-ba43-dac1f8f63013' must be configured via preauthorization - applications owned and operated by Microsoft must get approval from the API owner before requesting tokens for that API.

Within the error message, I know that 04b07795-8ddb-461a-bbee-02f9e1bf7b46 corresponds to Azure CLI, while 797f4846-ba00-4fd7-ba43-dac1f8f63013 maps to Azure Resource Manager. I don't believe that I can grant permissions/consent, as the 2 apps in question belong to Microsoft.

If I do a Fiddler trace, I can see the request below.

https://login.microsoftonline.com/organizations/oauth2/v2.0/authorize?scope=https://management.core.windows.net/scope+openid+profile+offline_access
&response_type=code
&client_id=04b07795-8ddb-461a-bbee-02f9e1bf7b46
&redirect_uri=http://localhost:8530
&client-request-id=603ffddb-0c62-48ed-84f3-fa99950c97ca
&x-client-SKU=MSAL.NetCore
&x-client-Ver=4.22.0.0
&x-client-OS=Microsoft+Windows+10.0.18363
&prompt=select_account
&code_challenge=<redacted>
&code_challenge_method=S256
&state=cfcedc3e-7ba2-42df-b578-4573391402f99671dee8-4459-474a-8d06-c1b197f03e89

The content matches pretty well what's discussed in this issue, only that it's a token for Microsoft Graph there, and one for Azure Resource Manager in my issue.

Is there work still underway to support the interactive login for my scenario, or is it something that I'm messing up on my end?
I'm getting this on both .NET Core 3.1 / .NET 5.

Note that if I'm using AzureCliCredential, as seen below, things work as expected:

AzureCliCredential credential = new AzureCliCredential();
Azure.Core.AccessToken authToken = credential.GetToken(new Azure.Core.TokenRequestContext(new string[] { "https://management.core.windows.net" }));

Environment:

  • Name and version of the Library package used: Azure Identity 1.3.0
  • Hosting platform or OS and .NET runtime version (dotnet --info output for .NET Core projects): Windows 10 .NET Core 3.1.2 / Windows 10 .NET 5.0.1
  • IDE and version : Visual Studio 16.5.0 Preview 5.0
@msftbot msftbot bot added needs-triage This is a new issue that needs to be triaged to the appropriate team. customer-reported Issues that are reported by GitHub users external to the Azure organization. question The issue doesn't require a change to the product in order to be resolved. Most issues start as that labels Dec 23, 2020
@jsquire jsquire added Azure.Identity Client This issue points to a problem in the data-plane of the library. needs-team-attention This issue needs attention from Azure service team or SDK team labels Dec 23, 2020
@msftbot msftbot bot removed the needs-triage This is a new issue that needs to be triaged to the appropriate team. label Dec 23, 2020
@jsquire
Copy link
Member

jsquire commented Dec 23, 2020

Thank you for your feedback. Tagging and routing to the team best able to assist. Please be aware that due to the holidays, responses may be delayed.

@luckerby
Copy link
Author

luckerby commented Jan 3, 2021

Appending /.default to the resource identifier, as instructed here will work just fine, and the interactive browser authentication process completes successfully. An added benefit is that this also works across multiple credential types, as in the same resource id can be passed to a DefaultAzureCredential, AzureCliCredential, etc
Leaving /default aside for a moment, one thing I don't quite understand is why some of the credential types will work with one form of resource id but not with another: eg SharedTokenCacheCredential works with https://management.core.windows.net/scope but not with https://management.core.windows.net, whereas AzureCliCredential works with https://management.core.windows.net but not with https://management.core.windows.net/scope.

@schaabs
Copy link
Contributor

schaabs commented Jan 7, 2021

@luckerby Sorry for the delayed response. I'm glad you were able unblock yourself. As to your question. https://management.core.windows.net is the resource string for ARM whereas https://management.core.windows.net/.default is a scope requesting the user_impersonation claim for the ARM resource. The reason for the two different formats for token claims requests is the AAD v1 protocol accepts resource strings whereas the AADv2 protocol accepts scopes. There are benefits to the newer protocol as it allows for requesting more specific access whereas in AAD v1 your essentially always requesting the user_impersonation claim, the /.default scope.

Unlike Graph, Azure hasn't fully transitioned to the v2 protocol, services generally only use user_impersonation as they use ARM RBAC to control user access, and lots of azure tooling, such as the Azure CLI still uses the v1 protocol. The Azure SDK attempts to abstract these gaps by only exposing the v2 protocol in the TokenCredential abstraction. This is why the TokenRequestContext accepts the argument scopes to it's constructor and has a Scopes property. All credentials should work with the scope https://management.core.windows.net/.default and if you have an instance where this is not the case it is certainly a bug.

However, I suspect the confusion here lies in the details of how Azure.Identity "converts" the v1 protocol to the v2 protocol. As I said above in v1 your essentially always requesting the user_impersonation claim, or the /.default scope, and currently this is the only scope needed for azure services. So the when the Azure.Identity library needs to turn a scope into a resource it will simply remove the /.default from the scope to get the resource string. However it doesn't error if the /.default is not present, in that case it returns the scope as is.

if (!scopes[0].EndsWith(DefaultSuffix, StringComparison.Ordinal))
{
return scopes[0];
}
return scopes[0].Remove(scopes[0].LastIndexOf(DefaultSuffix, StringComparison.Ordinal));

I believe this explains behavior you're seeing as the SharedTokenCacheCredential calls AAD directly so uses the v2 protocol, so if you request a resource string this will always fail. However, the AzureCliCredential calls az account get-access-token --resource <resource> which uses the v1 protocol and we need to convert the scope you've specified. Here we don't error when you specify a reasource string because it doesn't end in /.default so we simply return the scope as is. This happens to succeed since you passed the string we would have passed after striping /.default from the scope.

For all credentials in Azure.Identity it is always correct to pass https://management.core.windows.net/.default rather than https://management.core.windows.net. The confusion here is because we don't assert that the /.default portion of the scope is present. It could be argued that we should enforce that valid scopes are passed rather than resource string to avoid this confusing behavior, but properly enforcing this properly would be very difficult and would also be a breaking change.

I hope this helps, and I'm sorry for the confusion here. If you have more questions or would like more clarification you can post them here or DM me. I'm going to close this issue as you have fixed your initial issue, and I don't think the breaking change is warranted. If you disagree,
or if I have misunderstood your issue please reopen.

@schaabs schaabs closed this as completed Jan 7, 2021
@github-actions github-actions bot locked and limited conversation to collaborators Mar 28, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Azure.Identity Client This issue points to a problem in the data-plane of the library. customer-reported Issues that are reported by GitHub users external to the Azure organization. needs-team-attention This issue needs attention from Azure service team or SDK team question The issue doesn't require a change to the product in order to be resolved. Most issues start as that
Projects
None yet
Development

No branches or pull requests

3 participants