fix: MOS token device code fallback for macOS/Linux + remove dead AzureWebAppCreator#314
Conversation
…reWebAppCreator - MosTokenService: delegate to MsalBrowserCredential (useWam:false, custom authority) instead of calling AcquireTokenInteractive directly; eliminates PlatformNotSupportedException on macOS/Linux without a browser by inheriting MsalBrowserCredential's device code fallback - MsalBrowserCredential: add optional authority parameter to support government clouds (gcch/dod use login.microsoftonline.us) without defaulting to AzureCloudInstance.AzurePublic - MsalHelper: extract shared CreateDeviceCodeCallback to eliminate duplicate device code prompt display logic that existed in both MsalBrowserCredential and MosTokenService - MosTokenService: remove custom file-based token cache (mos-token-cache.json); MSAL's built-in persistent cache (DPAPI/Keychain/in-memory) replaces it with better security - MicrosoftGraphTokenProvider: raise LogDebug to LogWarning when MSAL fallback skipped due to missing clientAppId, making the silent failure path observable - AzureWebAppCreator: delete dead code -- CreateWebAppAsync was never called; setup infra creates web apps via az webapp create through CommandExecutor; remove from DI, all four command constructors, and both test files (23+11 constructor call sites cleaned up) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
There was a problem hiding this comment.
Pull request overview
This PR fixes a365 publish crashing on macOS/Linux with PlatformNotSupportedException during MOS token acquisition (issue #313) by making MosTokenService delegate to MsalBrowserCredential, which already has a device code fallback for headless environments. It also removes the dead AzureWebAppCreator class (never called in production) and refactors the shared device code prompt into a new MsalHelper helper.
Changes:
MosTokenServicenow delegates interactive auth toMsalBrowserCredential(withuseWam:false, per-environment authority) instead of callingAcquireTokenInteractivedirectly; removes custom file-based token cache in favor of MSAL's built-in persistent cacheMsalBrowserCredentialgains an optionalauthorityparameter (for government clouds) and deduplicates device code prompt logic via the newMsalHelper.CreateDeviceCodeCallbackAzureWebAppCreatordead code deleted, along with its DI registration and all constructor call sites in commands and tests
Reviewed changes
Copilot reviewed 15 out of 15 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
MosTokenService.cs |
Delegates to MsalBrowserCredential; removes file-based token cache and direct MSAL calls |
MsalBrowserCredential.cs |
Adds optional authority parameter; uses MsalHelper.CreateDeviceCodeCallback |
MsalHelper.cs |
New shared helper with CreateDeviceCodeCallback to eliminate duplicate prompt logic |
MicrosoftGraphTokenProvider.cs |
LogDebug → LogWarning for MSAL fallback skipped path |
AzureWebAppCreator.cs |
Deleted (dead code) |
Program.cs |
Removes AzureWebAppCreator DI registration and service resolution |
SetupCommand.cs |
Removes AzureWebAppCreator parameter |
AllSubcommand.cs |
Removes AzureWebAppCreator parameter |
BlueprintSubcommand.cs |
Removes AzureWebAppCreator parameter |
InfrastructureSubcommand.cs |
Removes AzureWebAppCreator parameter |
MosTokenServiceCacheTests.cs |
Deleted (file-based cache removed) |
MosTokenServiceTests.cs |
Removes [Collection] attribute no longer needed |
MsalBrowserCredentialTests.cs |
Adds tests for authority parameter |
SetupCommandTests.cs |
Removes _mockWebAppCreator from all test call sites |
BlueprintSubcommandTests.cs |
Removes _mockWebAppCreator from all test call sites |
Comments suppressed due to low confidence (1)
src/Microsoft.Agents.A365.DevTools.Cli/Services/MosTokenService.cs:84
- The new
catch (Exception ex)block catches all exceptions fromMsalBrowserCredential.GetTokenAsync(includingMsalAuthenticationFailedExceptionwith MSAL-specific error codes such asAADSTS650052,AADSTS50194, andinvalid_grant) and swallows them, returningnull. ThePublishCommand.cscaller has specificcatch (MsalServiceException)handlers for these error codes that provided tailored guidance; now those handlers are unreachable and users will only see the generic "Unable to acquire MOS token. Aborting publish." message regardless of the underlying cause.
If the MSAL-specific error codes need distinct guidance, consider extracting the per-code logic into MosTokenService (perhaps by catching MsalServiceException explicitly before the generic Exception) or re-throwing to let the caller handle them.
catch (Exception ex)
{
_logger.LogError(ex, "Failed to acquire MOS token: {Message}", ex.Message);
return null;
You can also share your feedback on Copilot code review. Take the survey.
…h blocks - Add MsalHelperTests.cs covering both branches of CreateDeviceCodeCallback: logger path (LogInformation called) and null-logger path (Console.Error written) - Move per-error-code MSAL guidance (AADSTS650052, AADSTS50194, invalid_grant) from PublishCommand into MosTokenService.LogMsalServiceError, where the auth concern belongs; catch MsalAuthenticationFailedException before catch Exception - Remove 4 permanently unreachable catch(MsalServiceException) blocks from PublishCommand — MosTokenService never propagates MsalServiceException - Fix stale invalid_grant guidance: remove reference to deleted mos-token-cache.json - Remove now-unused 'using Microsoft.Identity.Client' from PublishCommand.cs Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Remove AzureWebAppCreator, IPrerequisiteRunner, IAzureEnvironmentValidator from all command signatures (SetupCommand, AllSubcommand, BlueprintSubcommand, InfrastructureSubcommand) per PR #314 - Update Program.cs and test files to match new signatures - Retain PR #312 fixes: remove double logging in PrerequisiteRunner, fix \n in AppServiceAuthRequirementCheck resolution message, suppress pre-throw logging in ConfigService Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Closes #313