Closed
Description
Is your feature request related to a problem? Please describe.
The Azure SDK has the notion of TokenCredential which is used by various SDKs. It's possible to derive from TokenCredential to provide credentials coming from Microsoft.Identity.Web, however this requires both the token and the expiry. ITokenAcquisition covers the simple scenario where the token is returned, but not the expiry.
In a controller accessing a blob storage customers could write:
[AuthorizeForScopes(Scopes = new string[] { "https://storage.azure.com/user_impersonation" })]
public async Task<IActionResult> Blob()
{
var scopes = new string[] { "https://storage.azure.com/user_impersonation" }; // I guess the Blob SDK knows already?
ViewData["Message"] = await CreateBlob(new TokenAcquisitionTokenCredential(_tokenAcquisition),);
return View();
}
private static async Task<string> CreateBlob(TokenAcquisitionTokenCredential tokenCredential)
{
// Replace the URL below with the URL to your blob.
Uri blobUri = new Uri("https://storagesamples.blob.core.windows.net/sample-container/blob1.txt");
BlobClient blobClient = new BlobClient(blobUri, tokenCredential);
// Create a blob on behalf of the user.
string blobContents = "Blob created by Azure AD authenticated user.";
byte[] byteArray = Encoding.ASCII.GetBytes(blobContents);
using (MemoryStream stream = new MemoryStream(byteArray))
{
await blobClient.UploadAsync(stream);
}
return "Blob successfully created";
}
with
/// <summary>
/// Azure SDK token credential based on the ITokenAcquisition service.
/// </summary>
public class TokenAcquisitionTokenCredential : TokenCredential
{
private ITokenAcquisition _tokenAcquisition;
/// <summary>
/// Constructor from an ITokenAcquisition service.
/// </summary>
/// <param name="tokenAcquisition">Token acquisition.</param>
public TokenAcquisitionTokenCredential(ITokenAcquisition tokenAcquisition)
{
_tokenAcquisition = tokenAcquisition;
}
/// <inheritdoc/>
public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
{
AuthenticationResult result = _tokenAcquisition.GetAuthenticationResultForUserAsync(requestContext.Scopes)
.GetAwaiter()
.GetResult();
return new AccessToken(result.AccessToken, result.ExpiresOn);
}
/// <inheritdoc/>
public override async ValueTask<AccessToken> GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
{
AuthenticationResult result = await _tokenAcquisition.GetAuthenticationResultForUserAsync(requestContext.Scopes).ConfigureAwait(false);
return new AccessToken(result.AccessToken, result.ExpiresOn);
}
}
Describe the solution you'd like
- GetAuthenticationResultForUserAsync
- Expose TokenAcquisitionTokenCredential (given we already leverage the Azure.Identity NuGet package)
Describe alternatives you've considered
expose the expiry as an optional ref parameter?
- Expose TokenAcquisitionTokenCredential but not GetAuthenticationResultForUserAsync?
Additional context
- This is mainly a refactoring of GetTokenForUserAsync by exposing an intermediate product (the AuthenticationResult)
- Therefor no new tests are needed
- See the following experimental PR: Add support for the AzureSDK #542