-
Notifications
You must be signed in to change notification settings - Fork 254
Improved experience for Azure SDKs with Microsoft Identity Platform authentication #3416
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
894b3ec
4db1341
bf45363
5e46d3b
54bd932
b93b4cb
ca5a424
bd24816
2cf3777
dc1aece
ba44b61
2a9d15c
eff2121
376e092
cfdf484
d5927bc
994fff4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,170 @@ | ||||||
| # Microsoft.Identity.Web.Azure | ||||||
|
|
||||||
| [](https://www.nuget.org/packages/Microsoft.Identity.Web.Azure/) | ||||||
|
|
||||||
| This package enables ASP.NET Core web apps and web APIs to use the Azure SDKs with the Microsoft identity platform (formerly Azure AD v2.0). | ||||||
|
|
||||||
| ## Features | ||||||
|
|
||||||
| - **MicrosoftIdentityTokenCredential** - Provides seamless integration between Microsoft.Identity.Web and Azure SDK's TokenCredential, enabling your application to use Azure services with Microsoft Entra ID (formerly Azure Active Directory) authentication. | ||||||
| - Supports both user delegated and application permission scenarios | ||||||
| - Works with the standard Azure SDK authentication flow | ||||||
|
|
||||||
| ## Installation | ||||||
| dotnet add package Microsoft.Identity.Web.Azure | ||||||
| ## Usage | ||||||
|
|
||||||
| ### Basic setup | ||||||
|
|
||||||
| 1. Register the Azure Token Credential in your service collection: | ||||||
|
|
||||||
| ```cshap | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| // In your Startup.cs or Program.cs | ||||||
| using Azure.Storage.Blobs; | ||||||
| using Microsoft.Extensions.Azure; | ||||||
| using Microsoft.Extensions.DependencyInjection; | ||||||
| using Microsoft.Identity.Web; | ||||||
|
|
||||||
| public void ConfigureServices(IServiceCollection services) | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd suggest using the newer style (not a separate ConfigureServices method) |
||||||
| { | ||||||
| // Register Microsoft Identity Web | ||||||
| services.AddMicrosoftIdentityWebAppAuthentication(Configuration) | ||||||
| .EnableTokenAcquisitionToCallDownstreamApi() | ||||||
| .AddInMemoryTokenCaches(); | ||||||
|
|
||||||
| // Add the Azure Token Credential | ||||||
| services.AddMicrosoftIdentityAzureTokenCredential(); | ||||||
|
|
||||||
| // Register Azure services | ||||||
| services.AddAzureClients(builder => | ||||||
| { | ||||||
| // Use the Microsoft Identity credential for all Azure clients | ||||||
| builder.UseCredential(sp => sp.GetRequiredService<MicrosoftIdentityTokenCredential>()); | ||||||
|
|
||||||
| // Configure Azure Blob Storage client | ||||||
| builder.AddBlobServiceClient(new Uri("https://your-storage-account.blob.core.windows.net")); | ||||||
| // Add other Azure clients as needed | ||||||
| }); | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| ### Using with Azure SDK clients | ||||||
|
|
||||||
| Once registered, the BlobServiceClient can be injected directly into your controllers or services: | ||||||
| // Direct injection into a controller or Razor Page | ||||||
jmprieur marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
|
||||||
| ```csharp | ||||||
| [Authorize] | ||||||
| public class BlobController : Controller | ||||||
| { | ||||||
| private readonly BlobServiceClient _blobServiceClient; | ||||||
| private readonly MicrosoftIdentityTokenCredential _tokenCredential; | ||||||
|
|
||||||
| public BlobController( | ||||||
| BlobServiceClient blobServiceClient, | ||||||
| MicrosoftIdentityTokenCredential tokenCredential) // Optional: inject if you need to modify token behavior | ||||||
jmprieur marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| { | ||||||
| _blobServiceClient = blobServiceClient; | ||||||
| _tokenCredential = tokenCredential; | ||||||
| } | ||||||
|
|
||||||
| [HttpGet] | ||||||
| public async Task<IActionResult> DownloadBlob(string containerName, string blobName) | ||||||
| { | ||||||
| try | ||||||
| { | ||||||
| // If you want to have get a blob on behalf of the app itself. | ||||||
| _tokenCredential.Options.RequestAppToken = true; | ||||||
| var containerClient = _blobServiceClient.GetBlobContainerClient(containerName); | ||||||
| var blobClient = containerClient.GetBlobClient(blobName); | ||||||
|
|
||||||
| // Check if blob exists | ||||||
| if (!await blobClient.ExistsAsync()) | ||||||
| { | ||||||
| return NotFound($"Blob '{blobName}' not found in container '{containerName}'"); | ||||||
| } | ||||||
|
|
||||||
| // Download the blob content | ||||||
| var response = await blobClient.DownloadContentAsync(); | ||||||
| string content = response.Value.Content.ToString(); | ||||||
|
|
||||||
| return Content(content); | ||||||
| } | ||||||
| catch (Exception ex) | ||||||
| { | ||||||
| return StatusCode(500, $"Error accessing blob: {ex.Message}"); | ||||||
| } | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
| For Razor Pages, you can similarly inject the client directly: | ||||||
|
|
||||||
| ```csharp | ||||||
|
|
||||||
jmprieur marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
| public class BlobModel : PageModel | ||||||
| { | ||||||
| private readonly BlobServiceClient _blobServiceClient; | ||||||
|
|
||||||
| public BlobModel(BlobServiceClient blobServiceClient) | ||||||
| { | ||||||
| _blobServiceClient = blobServiceClient; | ||||||
| } | ||||||
|
|
||||||
| public async Task<IActionResult> OnGetAsync(string containerName, string blobName) | ||||||
| { | ||||||
| // Use the blob service client directly in your page handler | ||||||
| var containerClient = _blobServiceClient.GetBlobContainerClient(containerName); | ||||||
| // ...rest of the implementation | ||||||
| } | ||||||
| } | ||||||
| ``` | ||||||
|
|
||||||
|
|
||||||
| ### Advanced scenarios | ||||||
|
|
||||||
| #### Using with specific authentication schemes | ||||||
|
|
||||||
| If your application has multiple authentication schemes, you can specify which one to use: | ||||||
| // Configure the token credential to use a specific authentication scheme | ||||||
| tokenCredential.Options.AcquireTokenOptions.AuthenticationOptionsName = OpenIdConnectDefaults.AuthenticationScheme; | ||||||
|
|
||||||
| #### Custom configuration | ||||||
|
|
||||||
| You can customize the token acquisition behavior: | ||||||
| // Configure additional options | ||||||
| tokenCredential.Options.AcquireTokenOptions.CorrelationId = Guid.NewGuid(); | ||||||
| tokenCredential.Options.AcquireTokenOptions.Tenant = "GUID"; | ||||||
jmprieur marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
|
|
||||||
| ## Working with older versions | ||||||
|
|
||||||
| This package includes two token credentials classes: | ||||||
| - `MicrosoftIdentityTokenCredential` (recommended) | ||||||
jmprieur marked this conversation as resolved.
Show resolved
Hide resolved
|
||||||
| - `TokenAcquirerTokenCredential` (deprecated) | ||||||
|
|
||||||
| The `TokenAcquirerTokenCredential` is marked as obsolete and is included for backward compatibility. New applications should use `MicrosoftIdentityTokenCredential` instead. | ||||||
|
|
||||||
| ## Integration with Azure SDKs | ||||||
|
|
||||||
| This package enables integration with [Azure SDKs for .NET](https://learn.microsoft.com/dotnet/azure/sdk/azure-sdk-for-dotnet), including but not limited to: | ||||||
|
|
||||||
| - Azure Storage (Blobs, Queues, Tables, Files) | ||||||
| - Azure Key Vault (although you might rather want to use the DefaultCrentialLoader for credentials) | ||||||
| - Azure Service Bus | ||||||
| - Azure Cosmos DB | ||||||
| - Azure Event Hubs | ||||||
| - Azure Monitor | ||||||
|
|
||||||
| See [Azure SDK for .NET packages](https://learn.microsoft.com/dotnet/azure/sdk/packages#libraries-using-azurecore) | ||||||
| for the list of packages M | ||||||
jmprieur marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
|
||||||
| ## Related packages | ||||||
|
|
||||||
| - [Microsoft.Identity.Web](https://www.nuget.org/packages/Microsoft.Identity.Web/) | ||||||
| - [Microsoft.Identity.Web.UI](https://www.nuget.org/packages/Microsoft.Identity.Web.UI/) | ||||||
| - [Microsoft.Identity.Web.MicrosoftGraph](https://www.nuget.org/packages/Microsoft.Identity.Web.MicrosoftGraph/) | ||||||
|
|
||||||
| ## Learn more | ||||||
|
|
||||||
| - [Microsoft Identity Web documentation](https://aka.ms/ms-identity-web) | ||||||
| - [Azure SDK documentation](https://docs.microsoft.com/azure/developer/azure-sdk/) | ||||||
| - [Microsoft identity platform documentation](https://docs.microsoft.com/azure/active-directory/develop/) | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| Microsoft.Identity.Web.MicrosoftIdentityTokenCredential.MicrosoftIdentityTokenCredential(Microsoft.Identity.Abstractions.ITokenAcquirerFactory! tokenAcquirerFactory, Microsoft.Identity.Web.ITokenAcquisitionHost! tokenAcquisitionHost) -> void |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,75 @@ | ||||||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||||||
| // Licensed under the MIT License. | ||||||
|
|
||||||
| using System.Linq; | ||||||
| using System.Threading; | ||||||
| using System.Threading.Tasks; | ||||||
| using Azure.Core; | ||||||
| using Microsoft.Identity.Abstractions; | ||||||
|
|
||||||
| namespace Microsoft.Identity.Web | ||||||
| { | ||||||
| /// <summary> | ||||||
| /// Azure SDK token credential for tokens based on the <see cref="IAuthorizationHeaderProvider"/> | ||||||
| /// service. | ||||||
| /// </summary> | ||||||
| public class MicrosoftIdentityTokenCredential : TokenCredential | ||||||
| { | ||||||
| private ITokenAcquirerFactory _tokenAcquirerFactory; | ||||||
| private readonly IAuthenticationSchemeInformationProvider _authenticationSchemeInformationProvider; | ||||||
|
|
||||||
| /// <summary> | ||||||
| /// Constructor from an ITokenAcquisition service. | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This isn't clear to me |
||||||
| /// </summary> | ||||||
| /// <param name="tokenAcquirerFactory">Token acquisition factory</param> | ||||||
| /// <param name="authenticationSchemeInformationProvider">Host for the token acquisition</param> | ||||||
| public MicrosoftIdentityTokenCredential(ITokenAcquirerFactory tokenAcquirerFactory, IAuthenticationSchemeInformationProvider authenticationSchemeInformationProvider) | ||||||
| { | ||||||
| _tokenAcquirerFactory = tokenAcquirerFactory ?? throw new System.ArgumentNullException(nameof(tokenAcquirerFactory)); | ||||||
| _authenticationSchemeInformationProvider = authenticationSchemeInformationProvider ?? throw new System.ArgumentNullException(nameof(authenticationSchemeInformationProvider)); | ||||||
| } | ||||||
|
|
||||||
| AuthorizationHeaderProviderOptions _options = new AuthorizationHeaderProviderOptions(); | ||||||
|
|
||||||
| /// <summary> | ||||||
| /// Options used to configure the token acquisition behavior. | ||||||
| /// </summary> | ||||||
| public AuthorizationHeaderProviderOptions Options => _options; | ||||||
jmprieur marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||||||
|
|
||||||
| /// <inheritdoc/> | ||||||
| public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken) | ||||||
| { | ||||||
| ITokenAcquirer tokenAcquirer = _tokenAcquirerFactory.GetTokenAcquirer(_authenticationSchemeInformationProvider.GetEffectiveAuthenticationScheme(_options.AcquireTokenOptions.AuthenticationOptionsName)); | ||||||
|
||||||
| ITokenAcquirer tokenAcquirer = _tokenAcquirerFactory.GetTokenAcquirer(_authenticationSchemeInformationProvider.GetEffectiveAuthenticationScheme(_options.AcquireTokenOptions.AuthenticationOptionsName)); | |
| ITokenAcquirer tokenAcquirer = _tokenAcquirerFactory.GetTokenAcquirer(_authenticationSchemeInformationProvider.GetEffectiveAuthenticationScheme(Options.AcquireTokenOptions.AuthenticationOptionsName)); |
jmprieur marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should have a comment describing why the null suppression is safe.
jmprieur marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,8 @@ | ||
| #nullable enable | ||
| Microsoft.Identity.Web.MicrosoftIdentityTokenCredential | ||
| Microsoft.Identity.Web.MicrosoftIdentityTokenCredential.MicrosoftIdentityTokenCredential(Microsoft.Identity.Abstractions.ITokenAcquirerFactory! tokenAcquirerFactory, Microsoft.Identity.Web.IAuthenticationSchemeInformationProvider! authenticationSchemeInformationProvider) -> void | ||
| Microsoft.Identity.Web.MicrosoftIdentityTokenCredential.Options.get -> Microsoft.Identity.Abstractions.AuthorizationHeaderProviderOptions! | ||
| Microsoft.Identity.Web.ServiceCollectionExtensionForAzureCreds | ||
| override Microsoft.Identity.Web.MicrosoftIdentityTokenCredential.GetToken(Azure.Core.TokenRequestContext requestContext, System.Threading.CancellationToken cancellationToken) -> Azure.Core.AccessToken | ||
| override Microsoft.Identity.Web.MicrosoftIdentityTokenCredential.GetTokenAsync(Azure.Core.TokenRequestContext requestContext, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.ValueTask<Azure.Core.AccessToken> | ||
| static Microsoft.Identity.Web.ServiceCollectionExtensionForAzureCreds.AddMicrosoftIdentityAzureTokenCredential(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection! |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| using Microsoft.Extensions.DependencyInjection; | ||
|
|
||
| namespace Microsoft.Identity.Web | ||
| { | ||
| /// <summary> | ||
| /// Extensin methods for adding Azure credentials to the service collection. | ||
jmprieur marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| /// </summary> | ||
| public static class ServiceCollectionExtensionForAzureCreds | ||
| { | ||
| /// <summary> | ||
| /// Enables apps to use the <see cref="MicrosoftIdentityTokenCredential"/> for Azure AD authentication. | ||
| /// </summary> | ||
| /// <param name="services">Service collection where to add the <see cref="MicrosoftIdentityTokenCredential"/>.</param> | ||
| /// <returns>the service collection.</returns> | ||
jmprieur marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| public static IServiceCollection AddMicrosoftIdentityAzureTokenCredential(this IServiceCollection services) | ||
| { | ||
| services.AddScoped<MicrosoftIdentityTokenCredential>(); | ||
| return services; | ||
| } | ||
|
|
||
jmprieur marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,21 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| namespace Microsoft.Identity.Web | ||
| { | ||
| /// <summary> | ||
| /// Provides information about the effective authentication scheme. If passing null | ||
jmprieur marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| /// or string.Empty, this returns the default authentication scheme. | ||
| /// </summary> | ||
| public interface IAuthenticationSchemeInformationProvider | ||
|
|
||
| { | ||
| /// <summary> | ||
| /// Get the effective authentication scheme based on the provided authentication scheme. | ||
| /// </summary> | ||
| /// <param name="authenticationScheme">intended authentication scheme.</param> | ||
| /// <returns>Effective authentication scheme (default authentication scheme if the intended | ||
| /// authentication scheme is null or an empty string.</returns> | ||
| string GetEffectiveAuthenticationScheme(string? authenticationScheme); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,3 @@ | ||
| #nullable enable | ||
| Microsoft.Identity.Web.IAuthenticationSchemeInformationProvider | ||
| Microsoft.Identity.Web.IAuthenticationSchemeInformationProvider.GetEffectiveAuthenticationScheme(string? authenticationScheme) -> string! |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,3 @@ | ||
| #nullable enable | ||
| Microsoft.Identity.Web.IAuthenticationSchemeInformationProvider | ||
| Microsoft.Identity.Web.IAuthenticationSchemeInformationProvider.GetEffectiveAuthenticationScheme(string? authenticationScheme) -> string! |
Uh oh!
There was an error while loading. Please reload this page.