Skip to content

fix: Clear persisted MSAL token cache on Disconnect-MgGraph#3649

Merged
gavinbarron merged 9 commits into
mainfrom
gavinbarron/fix-disconnect-clear-token-cache
Jul 8, 2026
Merged

fix: Clear persisted MSAL token cache on Disconnect-MgGraph#3649
gavinbarron merged 9 commits into
mainfrom
gavinbarron/fix-disconnect-clear-token-cache

Conversation

@gavinbarron

Copy link
Copy Markdown
Member

Summary

Fixes #3648

When Disconnect-MgGraph is called with ContextScope == CurrentUser, the persisted MSAL token cache on disk was not being cleared. This PR adds cache clearing using MsalCacheHelper.Clear() from the MSAL Extensions library.

Changes

  • Added explicit Microsoft.Identity.Client.Extensions.Msal v4.78.0 package reference to Authentication.Core.csproj
  • Added TokenCacheUtilities.cs — builds StorageCreationProperties matching Azure.Identity's internal cache layout (Windows DPAPI, macOS Keychain, Linux KeyRing) and clears both .cae and .nocae cache variants
  • Modified AuthenticationHelpers.LogoutAsync() — calls TokenCacheUtilities.ClearPersistedTokenCacheAsync() when ContextScope == CurrentUser, with non-fatal error handling (disconnect still succeeds if cache clear fails)
  • Added unit tests for the new behavior
  • Updated Disconnect-MgGraph documentation

Design Decisions

  • Non-fatal error handling: Cache clearing failure does not prevent disconnect from succeeding — it's wrapped in try/catch
  • Both CAE variants cleared: Azure.Identity creates separate .cae and .nocae cache files; both are cleared
  • Matches Azure.Identity internals: StorageCreationProperties are configured to match the exact storage layout Azure.Identity uses (directory, keychain service, keyring schema/attributes)

Testing

  • 3 new unit tests added (all pass on net8.0 and net472)
  • All existing 77 tests continue to pass on net8.0

When ContextScope is CurrentUser, Disconnect-MgGraph now clears the
disk-persisted MSAL token cache (both .cae and .nocae variants) using
MsalCacheHelper.Clear() from Microsoft.Identity.Client.Extensions.Msal.

Previously only the in-memory cache and auth record file were cleared,
leaving cached tokens on disk that could be reused without
re-authentication.

Fixes #3648

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@gavinbarron gavinbarron requested a review from a team as a code owner June 22, 2026 23:26

@jsquire jsquire left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks correct to me, though I don't have a deep understanding in the area. I've asked @g2vinay and @JonathanCrd to also review. I'd consider them to be the authoritative voices from the Azure.Identity perspective.

ramsessanchez
ramsessanchez previously approved these changes Jun 23, 2026
@ramsessanchez

Copy link
Copy Markdown
Contributor

Approving the changes, however, in line with @jsquire 's comments, we should await feedback from the folks he mentioned. In order to reduce the change of needing a patch release later on, lets await their sign-off and before merging and releasing.

@gavinbarron

Copy link
Copy Markdown
Member Author

Agreed

Comment thread src/Authentication/Authentication.Core/Utilities/AuthenticationHelpers.cs Outdated

@JonathanCrd JonathanCrd left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall it looks good but I left a couple of comments about certain scenarios that might be missing and some questions too.

@g2vinay

g2vinay commented Jun 24, 2026

Copy link
Copy Markdown

Looks fine to me, left my comments on the ongoing discussions.

ramsessanchez and others added 3 commits June 29, 2026 11:32
…l WAM cache clearing

Adds an opt-in -SignOutFromBroker switch that removes cached accounts from the Windows broker (WAM) on disconnect. Because the broker store is shared at the OS level, this is opt-in to avoid signing users out of other broker-enabled apps by default.

Also replaces silent cache-clear catch blocks with best-effort WriteWarning/WriteDebug diagnostics so failures are diagnosable. All cache/broker clearing remains non-fatal.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
gavinbarron and others added 3 commits July 7, 2026 16:59
ClearBrokerTokenCacheAsync now removes only the account that signed in for the current session, matched via the persisted AuthenticationRecord.HomeAccountId against IAccount.HomeAccountId.Identifier. When no session account can be identified, it falls back to removing all accounts for the module.

This reduces the shared-broker blast radius so other accounts the user signed into via this module are left untouched.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ccount

ClearPersistedTokenCacheAsync now registers the on-disk MSAL cache with a public client application and removes only the current session's account (matched by HomeAccountId) from both the .cae and .nocae cache files. When no session account can be identified, it falls back to a full MsalCacheHelper.Clear().

HomeAccountId is now resolved once in LogoutAsync and shared between the file-cache and broker clearing paths for consistent, account-scoped sign-out.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… isolation

Captures the signed-in account's HomeAccountId on the session auth context at sign-in (interactive and device-code flows). LogoutAsync now scopes cache clearing on the session's own HomeAccountId, falling back to the shared auth record and then to a full clear.

This isolates Disconnect-MgGraph to the identity used in the current session, so other identities cached in the shared per-user store are preserved. HomeAccountId is read defensively so capturing this diagnostic id can never fail sign-in.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@gavinbarron gavinbarron enabled auto-merge (squash) July 8, 2026 00:37
gavinbarron and others added 2 commits July 7, 2026 17:45
Replaces the platyPS-generated '{{ Fill ProgressAction Description }}' placeholder with a proper description of the PowerShell 7.4+ ProgressAction common parameter.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The new -SignOutFromBroker switch raises the parameter count from 12 to 13 (SignOutFromBroker + PowerShell common parameters), so the Pester assertion is updated accordingly.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@gavinbarron gavinbarron merged commit f6d24ad into main Jul 8, 2026
7 checks passed
@gavinbarron gavinbarron deleted the gavinbarron/fix-disconnect-clear-token-cache branch July 8, 2026 23:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Disconnect-MgGraph does not clear the persisted MSAL token cache

5 participants