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

[BUG] AuthorizationCodeCredential does not allow Redirect URI to be defined #21529

Closed
clurdish opened this issue Jun 2, 2021 · 1 comment · Fixed by #21597
Closed

[BUG] AuthorizationCodeCredential does not allow Redirect URI to be defined #21529

clurdish opened this issue Jun 2, 2021 · 1 comment · Fixed by #21597
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 Workflow: 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

@clurdish
Copy link

clurdish commented Jun 2, 2021

Describe the bug
When utilizing AuthorizationCodeCredential to get an access token, an exception is thrown regarding the reply URL not being set.

The reply URL is set on the application registration to match the latter address. I was able to confirm that the portal is configured correctly by using a standard HTTP request on the oauth2 token endpoint - this worked correctly and I received an access token.

Expected behavior
The AuthorizationCodeCredential class should allow specification of the reply URL to use for gaining an access token. The documentation for the auth code flow here specifies that redirect_uri is a required parameter. Additionally, that documentation is referenced in the Azure SDK for .NET class documentation here.

Actual behavior (include Exception or Stack Trace)

AuthorizationCodeCredential authentication failed: A configuration issue is preventing authentication - check the error message from the server for details. You can modify the configuration in the application registration portal. See https://aka.ms/msal-net-invalid-client for details. Original exception: AADSTS500112: The reply address 'https://replyUrlNotSet' does not match the reply address 'http://localhost:7071/api/Redirect' provided when requesting Authorization code.

   at Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception ex)
   at Azure.Identity.AuthorizationCodeCredential.<GetTokenImplAsync>d__11.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Runtime.CompilerServices.ConfiguredValueTaskAwaitable`1.ConfiguredValueTaskAwaiter.GetResult()
   at Azure.Identity.AuthorizationCodeCredential.<GetTokenAsync>d__10.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
   at System.Threading.Tasks.ValueTask`1.get_Result()
   at System.Runtime.CompilerServices.ValueTaskAwaiter`1.GetResult()
   at [my code]

To Reproduce
Steps to reproduce the behavior (include a code snippet, screenshot, or any additional information that might help us reproduce the issue)

  1. Request an authorization code using the oauth2/authorize endpoint
  2. Once the user accepts and redirects to the specified reply url, use the code to obtain an access token via AuthorizationCodeCredential

Below is the azure function used to test this scenario. The custom Authorization.GetTokenAsync function using HttpClient works while using AuthorizationCodeCredential.GetTokenAsync throws the exception. I navigate to http://localhost:7071/api/Authorize in the browser, which redirects to MSFT authorize endpoint, accept scope, and it redirects to http://localhost:7071/api/Redirect.

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Collections.Specialized;
using Azure.Identity;
using System.Web.Http;
using Azure.Core;
using System.Net.Http;
using System.Collections.Generic;

namespace My.Authorization.Example
{
    public static class Authorization
    {
        private static readonly string tenantId = "<my tenant id>";
        private static readonly string clientId = "<my client id>";
        private static readonly string clientSecret = "<my client secret>";
        private static readonly string redirectUri = "http://localhost:7071/api/Redirect";
        private static readonly string scope = "https://analysis.windows.net/powerbi/api/.default";

        [FunctionName("Authorize")]
        public static async Task<IActionResult> Authorize(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
            ILogger log)
        {
            var queryString = System.Web.HttpUtility.ParseQueryString(string.Empty);
            queryString.Add(new NameValueCollection
            {
                { "response_type", "code" },
                { "client_id", clientId },
                { "resource", "https://analysis.windows.net/powerbi/api" },
                { "redirect_uri", redirectUri },
                { "response_mode", "query" },
                { "state", DateTime.Now.ToString("s") }
            });

            var url = $"https://login.microsoftonline.com/{tenantId}/oauth2/authorize?{queryString}";

            return new RedirectResult(url);
        }

        [FunctionName("Redirect")]
        public static async Task<IActionResult> Redirect(
            [HttpTrigger(AuthorizationLevel.Anonymous, "get", Route = null)] HttpRequest req,
            ILogger log)
        {
            try
            {
                var code = req.Query.GetString("code");
                var error = req.Query.GetString("error");
                var errorDesc = req.Query.GetString("error_description");
                var state = req.Query.GetString("state");

                //var token = await GetTokenAsync(code);
                var creds = new AuthorizationCodeCredential(tenantId, clientId, clientSecret, code);
                var token = await creds.GetTokenAsync(new TokenRequestContext(new string[]
                {
                    "https://analysis.windows.net/powerbi/api/.default"
                }));

                return new OkObjectResult("");
            }
            catch (Exception e)
            {
                log.LogError(e, "Failed to authorize with authorization code");
                return new InternalServerErrorResult();
            }
        }

        private static async Task<string> GetTokenAsync(string code)
        {
            using var client = new HttpClient();
            var url = $"https://login.microsoftonline.com/{tenantId}/oauth2/token";
            var res = await client.PostAsync(url, new FormUrlEncodedContent(new Dictionary<string, string>
            {
                { "client_id", clientId },
                { "scope", scope },
                { "code", code },
                { "redirect_uri", redirectUri },
                { "grant_type", "authorization_code" },
                { "client_secret", clientSecret }
            }));
            var content = await res.Content.ReadAsStringAsync();
            var token = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, string>>(content);
            return token["access_token"];
        }
    }

    public static class QueryCollectionExtensions
    {
        public static string GetString(this IQueryCollection collection, string key)
        {
            return collection.TryGetValue(key, out var val) ? val.ToString() : null;
        }
    }
}

Environment:

  • Name and version of the Library package used: Azure.Identity 1.4.0
  • Hosting platform or OS and .NET runtime version (dotnet --info output for .NET Core projects): Windows 10 .NET Core 3.1
  • IDE and version : Visual Studio 16.10.0
@ghost ghost added needs-triage Workflow: 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 Jun 2, 2021
@jsquire
Copy link
Member

jsquire commented Jun 2, 2021

Thank you for your feedback. Tagging and routing to the team members best able to assist.

@jsquire jsquire added Azure.Identity Client This issue points to a problem in the data-plane of the library. needs-team-attention Workflow: This issue needs attention from Azure service team or SDK team labels Jun 2, 2021
@ghost ghost removed the needs-triage Workflow: This is a new issue that needs to be triaged to the appropriate team. label Jun 2, 2021
@github-actions github-actions bot locked and limited conversation to collaborators Mar 27, 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 Workflow: 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

Successfully merging a pull request may close this issue.

4 participants