Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
using Microsoft.Agents.A365.DevTools.Cli.Services.Helpers;
using Microsoft.Agents.A365.DevTools.Cli.Services.Internal;
using Microsoft.Extensions.Logging;
using Microsoft.Identity.Client;
using System.CommandLine;
using System.IO.Compression;
using System.Net.Http.Headers;
Expand Down Expand Up @@ -355,66 +354,6 @@ public static Command CreateCommand(
mosToken = await mosTokenService.AcquireTokenAsync(mosEnv, mosPersonalToken);
logger.LogDebug("MOS token acquired successfully");
}
catch (MsalServiceException ex) when (ex.ErrorCode == "invalid_client" &&
ex.Message.Contains("AADSTS650052"))
{
logger.LogError("MOS token acquisition failed: Missing service principal or admin consent (Error: {ErrorCode})", ex.ErrorCode);
logger.LogInformation("");
logger.LogInformation("The MOS service principals exist, but admin consent may not be granted.");
logger.LogInformation("Grant admin consent at:");
logger.LogInformation(" {PortalUrl}",
MosConstants.GetApiPermissionsPortalUrl(config.ClientAppId));
logger.LogInformation("");
logger.LogInformation("Or authenticate interactively and consent when prompted.");
logger.LogInformation("");
return;
}
catch (MsalServiceException ex) when (ex.ErrorCode == "unauthorized_client" &&
ex.Message.Contains("AADSTS50194"))
{
logger.LogError("MOS token acquisition failed: Single-tenant app cannot use /common endpoint (Error: {ErrorCode})", ex.ErrorCode);
logger.LogInformation("");
logger.LogInformation("AADSTS50194: The application is configured as single-tenant but is trying to use the /common authority.");
logger.LogInformation("This should be automatically handled by using tenant-specific authority URLs.");
logger.LogInformation("");
logger.LogInformation("If this error persists:");
logger.LogInformation("1. Verify your app registration is configured correctly in Azure Portal");
logger.LogInformation("2. Check that tenantId in a365.config.json matches your app's home tenant");
logger.LogInformation("3. Ensure the app's 'Supported account types' setting matches your use case");
logger.LogInformation("");
return;
}
catch (MsalServiceException ex) when (ex.ErrorCode == "invalid_grant")
{
logger.LogError("MOS token acquisition failed: Invalid or expired credentials (Error: {ErrorCode})", ex.ErrorCode);
logger.LogInformation("");
logger.LogInformation("The authentication failed due to invalid credentials or expired tokens.");
logger.LogInformation("Try clearing the token cache and re-authenticating:");
logger.LogInformation(" - Delete: ~/.a365/mos-token-cache.json");
logger.LogInformation(" - Run: a365 publish");
logger.LogInformation("");
return;
}
catch (MsalServiceException ex)
{
// Log all MSAL-specific errors with full context for debugging
logger.LogError("MOS token acquisition failed with MSAL error");
logger.LogError("Error Code: {ErrorCode}", ex.ErrorCode);
logger.LogError("Error Message: {Message}", ex.Message);
logger.LogDebug("Stack Trace: {StackTrace}", ex.StackTrace);

logger.LogInformation("");
logger.LogInformation("Authentication failed. Common issues:");
logger.LogInformation("1. Missing admin consent - Grant at:");
logger.LogInformation(" {PortalUrl}",
MosConstants.GetApiPermissionsPortalUrl(config.ClientAppId));
logger.LogInformation("2. Insufficient permissions - Verify required API permissions are configured");
logger.LogInformation("3. Tenant configuration - Ensure app registration matches your tenant setup");
logger.LogInformation("");
logger.LogInformation("For detailed troubleshooting, search for error code: {ErrorCode}", ex.ErrorCode);
logger.LogInformation("");
return;
}
catch (Exception ex)
{
logger.LogError(ex, "Failed to acquire MOS token: {Message}", ex.Message);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ public static Command CreateCommand(
DeploymentService deploymentService,
IBotConfigurator botConfigurator,
IAzureValidator azureValidator,
AzureWebAppCreator webAppCreator,
PlatformDetector platformDetector,
GraphApiService graphApiService,
AgentBlueprintService blueprintService,
Expand All @@ -46,16 +45,16 @@ public static Command CreateCommand(
logger, configService, clientAppValidator));

command.AddCommand(InfrastructureSubcommand.CreateCommand(
logger, configService, azureValidator, webAppCreator, platformDetector, executor));
logger, configService, azureValidator, platformDetector, executor));

command.AddCommand(BlueprintSubcommand.CreateCommand(
logger, configService, executor, azureValidator, webAppCreator, platformDetector, botConfigurator, graphApiService, blueprintService, clientAppValidator, blueprintLookupService, federatedCredentialService));
logger, configService, executor, azureValidator, platformDetector, botConfigurator, graphApiService, blueprintService, clientAppValidator, blueprintLookupService, federatedCredentialService));

command.AddCommand(PermissionsSubcommand.CreateCommand(
logger, configService, executor, graphApiService, blueprintService));

command.AddCommand(AllSubcommand.CreateCommand(
logger, configService, executor, botConfigurator, azureValidator, webAppCreator, platformDetector, graphApiService, blueprintService, clientAppValidator, blueprintLookupService, federatedCredentialService));
logger, configService, executor, botConfigurator, azureValidator, platformDetector, graphApiService, blueprintService, clientAppValidator, blueprintLookupService, federatedCredentialService));

return command;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ public static Command CreateCommand(
CommandExecutor executor,
IBotConfigurator botConfigurator,
IAzureValidator azureValidator,
AzureWebAppCreator webAppCreator,
PlatformDetector platformDetector,
GraphApiService graphApiService,
AgentBlueprintService blueprintService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,6 @@ public static Command CreateCommand(
IConfigService configService,
CommandExecutor executor,
IAzureValidator azureValidator,
AzureWebAppCreator webAppCreator,
PlatformDetector platformDetector,
IBotConfigurator botConfigurator,
GraphApiService graphApiService,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ public static Command CreateCommand(
ILogger logger,
IConfigService configService,
IAzureValidator azureValidator,
AzureWebAppCreator webAppCreator,
PlatformDetector platformDetector,
CommandExecutor executor)
{
Expand Down
48 changes: 48 additions & 0 deletions src/Microsoft.Agents.A365.DevTools.Cli/Helpers/MsalHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using Microsoft.Extensions.Logging;
using Microsoft.Identity.Client;

namespace Microsoft.Agents.A365.DevTools.Cli.Helpers;

/// <summary>
/// Shared helpers for MSAL-based authentication flows used across multiple services.
/// </summary>
public static class MsalHelper
{
/// <summary>
/// Creates the standard MSAL device code callback that logs the verification URL and user code.
/// Shared across all interactive auth flows so the device code prompt is consistent.
/// </summary>
/// <param name="logger">Optional logger. When null, falls back to <see cref="Console.Error"/>.</param>
public static Func<DeviceCodeResult, Task> CreateDeviceCodeCallback(ILogger? logger)
{
return deviceCode =>
{
if (logger != null)
{
logger.LogInformation("");
logger.LogInformation("==========================================================================");
logger.LogInformation("To sign in, use a web browser to open the page:");
logger.LogInformation(" {VerificationUrl}", deviceCode.VerificationUrl);
logger.LogInformation("");
logger.LogInformation("And enter the code: {UserCode}", deviceCode.UserCode);
logger.LogInformation("==========================================================================");
logger.LogInformation("");
}
else
{
Console.Error.WriteLine();
Console.Error.WriteLine("==========================================================================");
Console.Error.WriteLine("To sign in, use a web browser to open the page:");
Console.Error.WriteLine($" {deviceCode.VerificationUrl}");
Console.Error.WriteLine();
Console.Error.WriteLine($"And enter the code: {deviceCode.UserCode}");
Console.Error.WriteLine("==========================================================================");
Console.Error.WriteLine();
}
return Task.CompletedTask;
};
}
}
6 changes: 1 addition & 5 deletions src/Microsoft.Agents.A365.DevTools.Cli/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ static async Task<int> Main(string[] args)
var agentBlueprintService = serviceProvider.GetRequiredService<AgentBlueprintService>();
var blueprintLookupService = serviceProvider.GetRequiredService<BlueprintLookupService>();
var federatedCredentialService = serviceProvider.GetRequiredService<FederatedCredentialService>();
var webAppCreator = serviceProvider.GetRequiredService<AzureWebAppCreator>();
var platformDetector = serviceProvider.GetRequiredService<PlatformDetector>();
var processService = serviceProvider.GetRequiredService<IProcessService>();
var clientAppValidator = serviceProvider.GetRequiredService<IClientAppValidator>();
Expand All @@ -111,7 +110,7 @@ static async Task<int> Main(string[] args)
rootCommand.AddCommand(DevelopCommand.CreateCommand(developLogger, configService, executor, authService, graphApiService, agentBlueprintService, processService));
rootCommand.AddCommand(DevelopMcpCommand.CreateCommand(developLogger, toolingService));
rootCommand.AddCommand(SetupCommand.CreateCommand(setupLogger, configService, executor,
deploymentService, botConfigurator, azureValidator, webAppCreator, platformDetector, graphApiService, agentBlueprintService, blueprintLookupService, federatedCredentialService, clientAppValidator));
deploymentService, botConfigurator, azureValidator, platformDetector, graphApiService, agentBlueprintService, blueprintLookupService, federatedCredentialService, clientAppValidator));
rootCommand.AddCommand(CreateInstanceCommand.CreateCommand(createInstanceLogger, configService, executor,
botConfigurator, graphApiService, azureValidator));
rootCommand.AddCommand(DeployCommand.CreateCommand(deployLogger, configService, executor,
Expand Down Expand Up @@ -253,9 +252,6 @@ private static void ConfigureServices(IServiceCollection services, LogLevel mini
services.AddSingleton<DelegatedConsentService>(); // For AgentApplication.Create permission
services.AddSingleton<ManifestTemplateService>(); // For publish command template extraction

// Register AzureWebAppCreator for SDK-based web app creation
services.AddSingleton<AzureWebAppCreator>();

// Register ProcessService for cross-platform process launching
services.AddSingleton<IProcessService, ProcessService>();

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ private async Task<CommandResult> ExecuteWithFallbackAsync(
{
if (string.IsNullOrWhiteSpace(clientAppId))
{
_logger.LogDebug("No client app ID available for MSAL Graph fallback.");
_logger.LogWarning("MSAL Graph fallback skipped: no client app ID available. Ensure ClientAppId is set in a365.config.json.");
return null;
}

Expand Down
Loading
Loading