openiddict-core
openiddict-core copied to clipboard
Enable the use of Azure Workload Identities with `.AddClient(options => { options.UseWebProviders().AddMicrosoft...})`
Confirm you've already contributed to this project or that you sponsor it
- [X] I confirm I'm a sponsor or a contributor
Describe the solution you'd like
The current implementation of .AddClient when using Microsoft Entra authentication looks as follows:
options.UseWebProviders()
.AddMicrosoft(options =>
{
options.SetClientId(Configuration["AzureAd:ClientId"]);
options.SetClientSecret(Configuration["AzureAd:ClientCredentials:0:ClientSecret"]);
options.SetTenant(Configuration["AzureAd:TenantId"]);
options.SetRedirectUri("callback/login/microsoft");
}
);
The options.SetClientSecret(Configuration["AzureAd:ClientCredentials:0:ClientSecret"]);
part is problematic for us since in all of our deployments we strive for credential-free configuration of all Azure-related service. To achieve this we make heavy use for Workload Identities (https://learn.microsoft.com/en-us/azure/aks/workload-identity-overview?tabs=dotnet).
Workload Identities essentially work by configuring the Kubernetes cluster as an OIDC provider and regarding the specific workload (i.e. the Pod on which the client is being served) as an identity on that provider. (This is achieved by injecting an identity token into the pod using a mutating webhook, but that isn't really important here). What is important is that the microsoft identity library is able to exchange that identity token for an access token against the Microsoft Entra application, thereby establishing authenticating client. Normally you would need a client secret to achieve that.
The vanilla builder.Services.AddAuthentication(AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
allows for this by setting the "SourceType" for client credentials to "SignedAssertionFilePath" (see https://github.com/AzureAD/microsoft-identity-web/wiki/v2.0#credentials-are-generalizing-certificates for more context),
Below would be the setup for a Workload Identity
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "xxxx-xxxx-xxxx-xxxx-xxxxxxxxx"
"ClientId": "xxxx-xxxx-xxxx-xxxx-xxxxxxxxx",
"ClientCredentials": [
{
"SourceType": "SignedAssertionFilePath"
}
]
},
The same setup using an explicit ClientSecret:
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"TenantId": "xxxx-xxxx-xxxx-xxxx-xxxxxxxxx"
"ClientId": "xxxx-xxxx-xxxx-xxxx-xxxxxxxxx",
"ClientCredentials": [
{
"ClientSecret": "f-D8Q~xxxxxxxxxxxxxxxxxx",
"SourceType": "ClientSecret"
}
],
},
We would like to have the ability to differentiate between these two approaches when using an OpenIddict client as well. For example, having a options.SetClientCredentials(Configuration["AzureAd:ClientCredentials"]);
setting that will behave differently depending on what has been set in "SourceType".
Additional context
No response