EDIT 10/24 I think this was all likely user error - see my answer below for remedy before getting too deep into this question
TL;DR: For my OAuth 2.0 code flow...
Why does my
TokenCredentials
not work with my AutoRest client? I'm getting NO bearer token applied to the request / no Authorization header set
I know my pipeline works already..
Using code from this azure sample, which is NOT an AutoRest client, I can successfully get my access_token
and can get JSON from my protected Web API project.. so I've ruled out all the prerequisite stuff.. I know my pipeline works
My AutoRest setup..
1.) Downloaded from GitHub this AutoRest repo v1.1.0
2.) Downloaded my swagger JSON to disk, saved as swagger.json
3.) Ran this command-line to generate C# files:
autorest --input-file=swagger.json --csharp --output-folder=MyCorp_ApiClient_Tsl --namespace='MyCorp.ApiClient' --add-credentials
4.) Copied generated classes into my .NET 4.6.2 web site
5.) These are my NuGets:
- Microsoft.Rest.ClientRuntime version="2.3.8"
- Microsoft.Rest.ClientRuntime.Azure.Authentication version="2.3.1"
- Microsoft.IdentityModel.Clients.ActiveDirectory version="2.28.3"
Here's what's not working:
AdalTokenHelper tokenHelper = new AdalTokenHelper();//helper code further below
string token = await tokenHelper.GetTokenString();
var svcClientCreds = new TokenCredentials(token, "Bearer");
client = new MyCorp.ApiClient(new Uri(apiRsrcUrl), svcClientCreds,
new DelegatingHandler[] { new MyAzureTracingHandler() });
//make call to OData controller...
MyCorp.ApiClient.Models.ODataResponseListStatus statusList = await client.Status.GetStatusAsync(expand: "StatusType",cancellationToken: defaultCancelThreadToken);
return View(statusList.Value);
I've tried variations of the above, using different ctor's of TokenCredentials
, but no matter, I can put my breakpoint in MyAzureTracingHandler
and see the request has no Authorization headers applied.. so I get the expected 401 Unauthorized
response.
If I modify MyAzureTracingHandler
to accept my instance of TokenCredentials
then I can force the request to have the appropriate bearer token applied..
This works, but, feels hack-ish:
I changed my original client instantiation snippet from this:
client = new ApiClient(new Uri(apiRsrcUrl), svcClientCreds,
new DelegatingHandler[] { new MyAzureTracingHandler() });
To this:
client = new ApiClient(new Uri(apiRsrcUrl), svcClientCreds,
new DelegatingHandler[] { new MyAzureTracingHandler(svcClientCreds) });
And inside the SendAsync
method of MyAzureTracingHander
I do this:
await svcClientCreds.ProcessHttpRequestAsync(request, cancellationToken);
Am I doing something wrong? I don't think I should have to pass the ServiceClientCredentials
in twice when instantiating my client.
Appendix A - Getting access token via ADAL:
private string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
private string appKey = ConfigurationManager.AppSettings["ida:ClientSecret"];
private string tslResourceID = ConfigurationManager.AppSettings["ross:TslWebApiResourceId"];
private static string loginRedirectUri = ConfigurationManager.AppSettings["ross:LoginRedirectUri"];
private AuthenticationContext authContext;
private AuthenticationResult authenticationResult;
public async Task<string> GetTokenString()
{
string signedInUserID = ClaimsPrincipal.Current.FindFirst(ClaimTypes.NameIdentifier).Value;
string tenantID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
string userObjectID = ClaimsPrincipal.Current.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
try
{
// get a token for the Graph without triggering any user interaction (from the cache, via multi-resource refresh token, etc)
ClientCredential clientcred = new ClientCredential(clientId, appKey);
// initialize AuthenticationContext with the token cache of the currently signed in user, as kept in the app's database
authContext = new AuthenticationContext(Startup.Authority, new ADALTokenCache(userObjectID));
UserIdentifier userIdentifier = new UserIdentifier(userObjectID, UserIdentifierType.UniqueId);
authenticationResult = await authContext.AcquireTokenSilentAsync(tslResourceID, clientcred, userIdentifier);
}
catch(AdalException ex)
{
throw ex;
}
return authenticationResult.AccessToken;
}
While I believe I ran my autorest
command with --add-credentials
it's possible I may have used the older syntax... --AddCredentials true
I also did not run autorest --reset
as the docs recommend you do
One of these is the culprit, because now my 1.1.0 autorest installation is generating everything correctly.