Azure-Samples / active-directory-dotnetcore-daemon-v2

A .NET Core daemon console application calling Microsoft Graph or your own WebAPI with its own identity
MIT License
242 stars 150 forks source link

System.InvalidOperationException : An invalid request URI was provided. Either the request URI must be an absolute URI or BaseAddress must be set. #198

Open sam-wheat opened 2 weeks ago

sam-wheat commented 2 weeks ago

System.InvalidOperationException : An invalid request URI was provided. Either the request URI must be an absolute URI or BaseAddress must be set.

This seems to be the default error message and it appears it gets thrown regardless of what error actually occurs.

For example I can shut down my api server and rather than get a 404 I get the error above.

I can also intentionally provide an invalid section name for the api config and I get the same error:

tokenAcquirerFactory.Configuration.GetSection("ThisDoesNotExist"); 

Now, I may be deserving of some error - but that error certainly seems like it is not the one I should be getting:

"MyApi": { 
    "BaseUrl": "https://localhost:5010/", 
    "RelativePath": "api/MyController/ThisMethod",
    "RequestAppToken": true,
    "Scopes": [ "api://yada-6e75f60a2ef7/.default" ] // . E.g. 'api://<API_APPLICATION_ID>/.default'
},

BaseUrl is provided and the RelativePath component is valid - even if it is invalid it is not malformed.

  IConfiguration appSettings = new ConfigurationBuilder().AddJsonFile(configFilePath, false).Build();
  var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
  tokenAcquirerFactory.Services.AddDownstreamApi("MyApi", appSettings);
  tokenAcquirerFactory.Configuration.GetSection("MyApi");
  var sp = tokenAcquirerFactory.Build();
  var api = sp.GetRequiredService<IDownstreamApi>();
  string result = await api.GetForAppAsync<string>("MyAPI");  

How can I troubleshoot this error?

jmprieur commented 2 weeks ago

You need to do that:

 - IConfiguration appSettings = new ConfigurationBuilder().AddJsonFile(configFilePath, false).Build();
  var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
-  tokenAcquirerFactory.Services.AddDownstreamApi("MyApi", appSettings);
+  tokenAcquirerFactory.Services.AddDownstreamApi("MyApi", tokenAcquirerFactory.Configuration.GetSection("MyApi"));
  var sp = tokenAcquirerFactory.Build();
  var api = sp.GetRequiredService<IDownstreamApi>();
  string result = await api.GetForAppAsync<string>("MyAPI"); 

but you also need an "AzureAd" section unless you want to use Managed identity

sam-wheat commented 2 weeks ago

Thank you @jmprieur

My config file does not exist in the bin folder so I create it manually and pass it to AddDownstreamApi:

IConfiguration appSettings = new ConfigurationBuilder().AddJsonFile(configFilePath, false).Build();

The config file does have an AzureAd section. Are you saying that is what is causing the problem? If so, how can I use a config file that does not get copied to bin (secrets file)? In prod it will get copied - however in dev the config file is not source controlled so I hardcode a path and load it as shown.

sam-wheat commented 1 week ago

I'm still stuck on this - any suggestions how to get around this error?