File: EntraIdUrls.cs
Web Access
Project: src\src\Aspire.Hosting.Azure.EntraId\Aspire.Hosting.Azure.EntraId.csproj (Aspire.Hosting.Azure.EntraId)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
namespace Aspire.Hosting.Azure;
 
/// <summary>
/// Builds the links that the dashboard shows for an Entra ID application.
/// </summary>
internal static class EntraIdUrls
{
    /// <summary>
    /// Gets the URL of the OpenID Connect discovery document for the authority that Microsoft.Identity.Web uses.
    /// </summary>
    /// <param name="instance">The Entra ID instance, such as <c>https://login.microsoftonline.com/</c>.</param>
    /// <param name="tenant">
    /// The tenant segment of the authority: the home tenant for single-tenant apps, or the sign-in audience keyword,
    /// such as <c>organizations</c>, for the other audiences.
    /// </param>
    /// <remarks>
    /// Microsoft.Identity.Web builds the authority as <c>{Instance}/{TenantId}/v2.0</c> and discovers the endpoints
    /// and signing keys from this document, so opening it shows what the referencing apps will use.
    /// For more information, see
    /// <a href="https://learn.microsoft.com/entra/identity-platform/v2-protocols-oidc#find-your-apps-openid-configuration-document-uri">Find your app's OpenID configuration document URI</a>.
    /// </remarks>
    internal static string GetOpenIdConfigurationUrl(string instance, string tenant)
        => $"{instance.TrimEnd('/')}/{tenant}/v2.0/.well-known/openid-configuration";
 
    /// <summary>
    /// Gets a link to the app registration's Overview page in the portal for the instance's cloud,
    /// or <see langword="null"/> when that portal is not known.
    /// </summary>
    /// <param name="instance">The Entra ID instance, such as <c>https://login.microsoftonline.com/</c>.</param>
    /// <param name="homeTenantId">The ID or domain of the tenant where the app is registered.</param>
    /// <param name="clientId">The application (client) ID of the app registration.</param>
    internal static string? GetPortalUrl(string instance, string homeTenantId, string clientId)
    {
        if (!Uri.TryCreate(instance, UriKind.Absolute, out var uri) || GetPortalHost(uri.Host) is not { } portalHost)
        {
            return null;
        }
 
        // "#@{tenant}" makes the portal switch to the app's home tenant before opening the blade. Without it, the
        // portal looks for the registration in the signed-in user's default directory, which fails for developers
        // whose app is registered in another tenant.
        return $"https://{portalHost}/#@{homeTenantId}/view/Microsoft_AAD_RegisteredApps/ApplicationMenuBlade/~/Overview/appId/{clientId}/isMSAApp~/false";
    }
 
    // Maps the instance's sign-in host to the portal of the same cloud. Uri lowercases the host, so the comparisons
    // can be ordinal. The national cloud hosts are listed at
    // https://learn.microsoft.com/entra/identity-platform/authentication-national-cloud#microsoft-entra-authentication-endpoints
    private static string? GetPortalHost(string loginHost) => loginHost switch
    {
        "login.microsoftonline.com" or "login.microsoft.com" or "login.windows.net" => "portal.azure.com",
        "login.microsoftonline.us" => "portal.azure.us",
        "login.chinacloudapi.cn" or "login.partner.microsoftonline.cn" => "portal.azure.cn",
 
        // External tenants sign users in at "{tenant}.ciamlogin.com" and are managed in the Microsoft Entra admin center.
        _ when loginHost.EndsWith(".ciamlogin.com", StringComparison.Ordinal) => "entra.microsoft.com",
 
        // Private clouds, emulators and proxies have no known portal, and a link to another cloud's portal would mislead.
        _ => null
    };
}