Skip to content

Commit

Permalink
chore: Update .NET sample to use MSAL best practices (#1146)
Browse files Browse the repository at this point in the history
Co-authored-by: Anish Ramasekar <[email protected]>
  • Loading branch information
bgavrilMS and aramase authored Dec 11, 2023
1 parent 0fb935f commit 6217742
Showing 1 changed file with 25 additions and 6 deletions.
31 changes: 25 additions & 6 deletions examples/msal-net/akvdotnet/TokenCredential.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
using Microsoft.Identity.Client;
using System.Threading;
using System.Threading.Tasks;
using System.Data;
// <directives>

public class MyClientAssertionCredential : TokenCredential
{
private readonly IConfidentialClientApplication _confidentialClientApp;
private DateTimeOffset _lastRead;
private string _lastJWT = null;

public MyClientAssertionCredential()
{
Expand All @@ -17,14 +20,19 @@ public MyClientAssertionCredential()
// AZURE_CLIENT_ID with the clientID set in the service account annotation
// AZURE_TENANT_ID with the tenantID set in the service account annotation. If not defined, then
// the tenantID provided via azure-wi-webhook-config for the webhook will be used.
// AZURE_AUTHORITY_HOST is the Microsoft Entra authority host. It is https://login.microsoftonline.com" for the public cloud.
// AZURE_FEDERATED_TOKEN_FILE is the service account token path
var clientID = Environment.GetEnvironmentVariable("AZURE_CLIENT_ID");
var tokenPath = Environment.GetEnvironmentVariable("AZURE_FEDERATED_TOKEN_FILE");
var tenantID = Environment.GetEnvironmentVariable("AZURE_TENANT_ID");
var host = Environment.GetEnvironmentVariable("AZURE_AUTHORITY_HOST");

_confidentialClientApp = ConfidentialClientApplicationBuilder.Create(clientID)
.WithClientAssertion(ReadJWTFromFS(tokenPath))
.WithTenantId(tenantID).Build();
_confidentialClientApp = ConfidentialClientApplicationBuilder
.Create(clientID)
.WithAuthority(host, tenantID)
.WithClientAssertion(() => ReadJWTFromFSOrCache(tokenPath)) // ReadJWTFromFS should always return a non-expired JWT
.WithCacheOptions(CacheOptions.EnableSharedCacheOptions) // cache the the AAD tokens in memory
.Build();
}

public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
Expand Down Expand Up @@ -55,9 +63,20 @@ public override async ValueTask<AccessToken> GetTokenAsync(TokenRequestContext r
return new AccessToken(result.AccessToken, result.ExpiresOn);
}

public string ReadJWTFromFS(string tokenPath)
/// <summary>
/// Read the JWT from the file system, but only do this every few minutes to avoid heavy I/O.
/// The JWT lifetime is anywhere from 1 to 24 hours, so we can safely cache the value for a few minutes.
/// </summary>
private string ReadJWTFromFSOrCache(string tokenPath)
{
string text = System.IO.File.ReadAllText(tokenPath);
return text;
// read only once every 5 minutes
if (_lastJWT == null ||
DateTimeOffset.UtcNow.Subtract(_lastRead) > TimeSpan.FromMinutes(5))
{
_lastRead = DateTimeOffset.UtcNow;
_lastJWT = System.IO.File.ReadAllText(tokenPath);
}

return _lastJWT;
}
}

0 comments on commit 6217742

Please sign in to comment.