PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0

Sunday, September 4, 2022

[FIXED] How to store Azure AD PublicClientApplication AuthenticationResult tokens on disk

 September 04, 2022     .net, authentication, azure, azure-active-directory, c#     No comments   

Issue

Using PublicClientApplicationBuilder I build an IPublicClientApplication that I use to access some services within Azure Devops programatically.

This app is short lived however, it spins up, performs a task (in this case triggering builds) then spins down. At this point the tokens gained from an interactive login are lost, and the next time the app runs, I need to login again.

Is there any way to set a token cache to be on disk or a blob store or something so that this app can run, grab a token from the cache and work without me having to login every time?

I call AcquireTokenSilent a second time at the end there, and it works, after I've got my token with DeviceCode, it is able to gain another token silently. But once this app ends and restarts that cache seems to clear. Is there any way to store it somewhere? A cookie/disk etc? Or should this be cached in azure somehow and mine just isn't working? Or needs configured differently?

Application = PublicClientApplicationBuilder.Create(ClientId)
    .WithAuthority(Authority)
    .WithDefaultRedirectUri()
    .Build();


AuthenticationResult result = null;

var accounts = await Application.GetAccountsAsync();
// Try to acquire an access token from the cache. If device code is required, Exception will be thrown.
if (accounts.Any()) //There is never any accounts in the cache, as this is always run from app startup
{
    result = await Application.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
        .ExecuteAsync();
}
else
{
    //This works fine, but I need to interact and login every time.
    result = await Application.AcquireTokenWithDeviceCode(scopes, deviceCodeResult =>
    {
        Console.WriteLine(deviceCodeResult.Message);
        return Task.FromResult(0);
    }).ExecuteAsync();
}

//Now that I have logged in this works fine
accounts = await Application.GetAccountsAsync();
result = await Application.AcquireTokenSilent(scopes, accounts.FirstOrDefault())
    .ExecuteAsync();

Solution

Ok, I figured this out. Ideally I should be using an encrypted keychain etc.. and I am aware that this is unsecure, but I will improve with keychain use in the future.

This solution, however unsecure, caches the information to a local file, and it can be used after an application restart.

var directory = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
var storageProperties =
    new StorageCreationPropertiesBuilder("authcache", directory)
        .WithUnprotectedFile()
        .Build();

var cacheHelper = await MsalCacheHelper.CreateAsync(
    storageProperties).ConfigureAwait(false);

cacheHelper.VerifyPersistence();

// Initialize the MSAL library by building a public client application
Application = PublicClientApplicationBuilder.Create(ClientId)
    .WithAuthority(Authority)
    .WithLegacyCacheCompatibility()
    .WithDefaultRedirectUri()
    .Build();

// This hooks up the cross-platform cache into MSAL
cacheHelper.RegisterCache(Application.UserTokenCache);


Answered By - Mark McGookin
Answer Checked By - Senaida (PHPFixing Volunteer)
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Newer Post Older Post Home

0 Comments:

Post a Comment

Note: Only a member of this blog may post a comment.

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
Comments
Atom
Comments

Copyright © PHPFixing