The POC
Creates a new Console project and then add Microsoft.IdentityModel.Clients.ActiveDirectory package.Now add this class to your project
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
namespace ClientFor1MApi
{
public class ActiveDirectoryAuthHandler : DelegatingHandler
{
private const int maxAuthRetry = 3;
private readonly AuthenticationContext authContext;
private readonly ClientCredential clientCredential;
private readonly string appIdUri;
public ActiveDirectoryAuthHandler(AuthenticationContext authContext
, ClientCredential clientCredential
, string appIdUri
, HttpMessageHandler innerHandler) : base(innerHandler)
{
this.authContext = authContext ?? throw new ArgumentNullException(nameof(authContext));
this.clientCredential = clientCredential ?? throw new ArgumentNullException(nameof(clientCredential));
this.appIdUri = appIdUri ?? throw new ArgumentNullException(nameof(appIdUri));
}
public ActiveDirectoryAuthHandler(AuthenticationContext authContext
, ClientCredential clientCredential
, string appIdUri) : base(new HttpClientHandler())
{
this.authContext = authContext ?? throw new ArgumentNullException(nameof(authContext));
this.clientCredential = clientCredential ?? throw new ArgumentNullException(nameof(clientCredential));
this.appIdUri = appIdUri ?? throw new ArgumentNullException(nameof(appIdUri));
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var authResult = await GetAuth();
if (authResult != null)
{
request.Headers.Authorization = new AuthenticationHeaderValue(authResult.AccessTokenType, authResult.AccessToken);
}
return await base.SendAsync(request, cancellationToken);
}
private async Task<AuthenticationResult> GetAuth()
{
int retryCount = 0;
bool mustRetry;
do
{
mustRetry = false;
try
{
// ADAL includes an in memory cache, so this call will only send a message to the server if the cached token is expired.
return await authContext.AcquireTokenAsync(appIdUri, clientCredential);
}
catch (AdalException ex) when (ex.ErrorCode == "temporarily_unavailable")
{
mustRetry = true;
retryCount++;
await Task.Delay(3000);
}
} while ((mustRetry == true) && (retryCount < maxAuthRetry));
return null;
}
}
}
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading;
using System.Threading.Tasks;
namespace ClientFor1MApi
{
public class ActiveDirectoryAuthHandler : DelegatingHandler
{
private const int maxAuthRetry = 3;
private readonly AuthenticationContext authContext;
private readonly ClientCredential clientCredential;
private readonly string appIdUri;
public ActiveDirectoryAuthHandler(AuthenticationContext authContext
, ClientCredential clientCredential
, string appIdUri
, HttpMessageHandler innerHandler) : base(innerHandler)
{
this.authContext = authContext ?? throw new ArgumentNullException(nameof(authContext));
this.clientCredential = clientCredential ?? throw new ArgumentNullException(nameof(clientCredential));
this.appIdUri = appIdUri ?? throw new ArgumentNullException(nameof(appIdUri));
}
public ActiveDirectoryAuthHandler(AuthenticationContext authContext
, ClientCredential clientCredential
, string appIdUri) : base(new HttpClientHandler())
{
this.authContext = authContext ?? throw new ArgumentNullException(nameof(authContext));
this.clientCredential = clientCredential ?? throw new ArgumentNullException(nameof(clientCredential));
this.appIdUri = appIdUri ?? throw new ArgumentNullException(nameof(appIdUri));
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
var authResult = await GetAuth();
if (authResult != null)
{
request.Headers.Authorization = new AuthenticationHeaderValue(authResult.AccessTokenType, authResult.AccessToken);
}
return await base.SendAsync(request, cancellationToken);
}
private async Task<AuthenticationResult> GetAuth()
{
int retryCount = 0;
bool mustRetry;
do
{
mustRetry = false;
try
{
// ADAL includes an in memory cache, so this call will only send a message to the server if the cached token is expired.
return await authContext.AcquireTokenAsync(appIdUri, clientCredential);
}
catch (AdalException ex) when (ex.ErrorCode == "temporarily_unavailable")
{
mustRetry = true;
retryCount++;
await Task.Delay(3000);
}
} while ((mustRetry == true) && (retryCount < maxAuthRetry));
return null;
}
}
}
The HtppMessageHandler needs three parameters: AuthenticationContext, ClientCredential and appIDUri. To create each one we needs some information we have seen in the previous post and to be consistent I will reuse the same images.
The AuthenticationContext
To create an instance of the AuthenticationContext we need only the URL of the AAD where our API-app and our client are registered. It should look something like this:The ClientCredential
To create an instance of ClientCredential we need the “Application ID” and the “Key” of our client registered un our AAD:the Application ID is
the key is
The appIDUri
The App ID URI is the value we give to our API-app registered in our AADThe usage of ActiveDirectoryAuthHandler
public class Program
{
static void Main(string[] args)
{
var aadInstance = "https://login.microsoftonline.com/yourAaadDomain.onmicrosoft.com";
var clientAppId = "1e852e38-2ef9-439b-b696-dccaa811562c";
var clientAppKey = "vRSDlEOAFrYi59zoVQyuamJv0ZPRegZTd87ugngD8aU=";
var apiAppIdUri = "https://The1MApi.azurewebsites.net";
var httpClient = new HttpClient(new ActiveDirectoryAuthHandler(
new AuthenticationContext(aadInstance)
, new ClientCredential(clientAppId, clientAppKey)
, apiAppIdUri
))
{
BaseAddress= new Uri("https://The1MApi.azurewebsites.net")
};
var _ = httpClient.PostAsync("api/values"
, new FormUrlEncodedContent(new Dictionary<string, string> { { "value", "a new value from client" } })).Result;
var response = httpClient.GetAsync("api/values").Result;
Console.Write(response.Content.ReadAsStringAsync().Result);
Console.ReadLine();
}
}
{
static void Main(string[] args)
{
var aadInstance = "https://login.microsoftonline.com/yourAaadDomain.onmicrosoft.com";
var clientAppId = "1e852e38-2ef9-439b-b696-dccaa811562c";
var clientAppKey = "vRSDlEOAFrYi59zoVQyuamJv0ZPRegZTd87ugngD8aU=";
var apiAppIdUri = "https://The1MApi.azurewebsites.net";
var httpClient = new HttpClient(new ActiveDirectoryAuthHandler(
new AuthenticationContext(aadInstance)
, new ClientCredential(clientAppId, clientAppKey)
, apiAppIdUri
))
{
BaseAddress= new Uri("https://The1MApi.azurewebsites.net")
};
var _ = httpClient.PostAsync("api/values"
, new FormUrlEncodedContent(new Dictionary<string, string> { { "value", "a new value from client" } })).Result;
var response = httpClient.GetAsync("api/values").Result;
Console.Write(response.Content.ReadAsStringAsync().Result);
Console.ReadLine();
}
}