The support for ADAL ends on June 30, 2022 and Microsoft recommends migrating applications to MSAL.
During migration, I encountered a difficulty migrating a code that accesses Data Lake Storage from ADAL to MSAL. My almost-working attempt is:
// Before migration (authenticate using obsolete ADAL)
ClientCredential clientCredential = new ClientCredential(clientId, clientSecret);
ServiceClientCredentials credentials = await ApplicationTokenProvider.LoginSilentAsync(tenantId, clientCredential);
var adlsClient = AdlsClient.CreateClient(dataLakeStoreName, serviceCredentials)
// After migration (authenticate using newer MSAL)
var clientApplication = ConfidentialClientApplicationBuilder
.Create(clientId)
.WithClientSecret(clientSecrret)
.WithAuthority(new Uri($"https://login.microsoftonline.com/{tenantId}"))
.Build();
AuthenticationResult credentials = await (new[] { $"https://datalake.azure.net/.default" })
.ExecuteAsync();
// We no longer have ServiceClientCredentials object, so the only overload left is the one that accepts a bearer token as a string:
var adlsClient = AdlsClient
.CreateClient(dataLakeStoreName, $"{credentials.TokenType} {credentials.AccessToken}");
The above MSAL code works for a while, but with ServiceClientCredentials
gone, we lost the object responsible for refreshing a token. So, when the token expires, adlsClient
now stops working.
Is there any simple way to create a ServiceClientCredentials
with MSAL?
Or do we need to code the logic that refreshes the token ourselves when we migrate to MSAL?
>Solution :
Got same problem lately. You can implement your own ServiceClientCredentials
that can utilize IConfidentialClientApplication
to manage access token. For example:
public class DataLakeGen1ClientCredentials : ServiceClientCredentials
{
private readonly IConfidentialClientApplication _application;
public DataLakeGen1ClientCredentials(string? appId, string? secretKey, string? directoryId)
{
_application = ConfidentialClientApplicationBuilder
.Create(appId)
.WithClientSecret(secretKey)
.WithAuthority(new Uri($"https://login.microsoftonline.com/{directoryId}"))
.Build();
}
public override async Task ProcessHttpRequestAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
HttpRequestHeaders httpRequestHeaders = request.Headers;
var authResult = await _application.AcquireTokenForClient(new[] { $"https://datalake.azure.net/.default" })
.ExecuteAsync(cancellationToken).ConfigureAwait(false);
httpRequestHeaders.Authorization = new AuthenticationHeaderValue(authResult.TokenType, authResult.AccessToken);
await base.ProcessHttpRequestAsync(request, cancellationToken).ConfigureAwait(false);
}
}
Than you can use it to init your adlsClient
:
var serviceCredentials = new DataLakeGen1ClientCredentials(clientId, clientSecret, tenantId);
AdlsClient client = AdlsClient.CreateClient(DataLakeStoreName, serviceCredentials);