Psychonaut007
Psychonaut007

Reputation: 197

How to make a startup class for multi-tenant compatible with single tenant?

So I am trying to access graph api from my webapp in order to receive email of the user. I dont want to save the token. I have followed this tutorial but it turns out its for the multi-tenant. This is my startup class:

[assembly: OwinStartup(typeof(Zeus.Web.Startup))]

namespace WebApp
{
    public partial class Startup
    {
        // Load configuration settings from PrivateSettings.config
        private static string appId = ConfigurationManager.AppSettings["ida:AppId"];
        private static string appSecret = ConfigurationManager.AppSettings["ida:AppSecret"];
        private static string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];
        private static string graphScopes = ConfigurationManager.AppSettings["ida:AppScopes"];
        //private static string aadInstance = EnsureTrailingSlash(ConfigurationManager.AppSettings["ida:AADInstance"]);

        public void Configuration(IAppBuilder app)
        {
            // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

            app.UseCookieAuthentication(new CookieAuthenticationOptions());

            app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    ClientId = appId,
                    Authority = "https://login.microsoftonline.com/common/v2.0",
                    Scope = $"openid email profile offline_access {graphScopes}",
                    RedirectUri = redirectUri,
                    PostLogoutRedirectUri = redirectUri,
                    TokenValidationParameters = new TokenValidationParameters
                    {
                        // For demo purposes only, see below
                        ValidateIssuer = true

                        // In a real multi-tenant app, you would add logic to determine whether the
                        // issuer was from an authorized tenant
                        //ValidateIssuer = true,
                        //IssuerValidator = (issuer, token, tvp) =>
                        //{
                        //  if (MyCustomTenantValidation(issuer))
                        //  {
                        //    return issuer;
                        //  }
                        //  else
                        //  {
                        //    throw new SecurityTokenInvalidIssuerException("Invalid issuer");
                        //  }
                        //}
                    },
                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        AuthenticationFailed = OnAuthenticationFailedAsync,
                        AuthorizationCodeReceived = OnAuthorizationCodeReceivedAsync
                    }
                }
            );
        }
        private static Task OnAuthenticationFailedAsync(AuthenticationFailedNotification<OpenIdConnectMessage,
            OpenIdConnectAuthenticationOptions> notification)
        {
            notification.HandleResponse();
            string redirect = $"/Home/Error?message={notification.Exception.Message}";
            if (notification.ProtocolMessage != null && !string.IsNullOrEmpty(notification.ProtocolMessage.ErrorDescription))
            {
                redirect += $"&debug={notification.ProtocolMessage.ErrorDescription}";
            }
            notification.Response.Redirect(redirect);
            return Task.FromResult(0);
        }

        private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedNotification notification)
        {
            var idClient = ConfidentialClientApplicationBuilder.Create(appId)
                .WithRedirectUri(redirectUri)
                .WithClientSecret(appSecret)
                .Build();

            string email = string.Empty;
            try
            {
                string[] scopes = graphScopes.Split(' ');

                var result = await idClient.AcquireTokenByAuthorizationCode(
                    scopes, notification.Code).ExecuteAsync();

                email = await GraphHelper.GetUserDetailsAsync(result.AccessToken);
            }
            catch (MsalException ex)
            {
                System.Diagnostics.Trace.TraceError(ex.Message);
            }
            notification.HandleResponse();
            notification.Response.Redirect($"/Account/SignInAzure?email={email}");
        }

    }
}

Can anyone suggest me what changes I need to look for into it for making it compatible with the single tenant. The error I am receiving:

"OpenIdConnectMessage.Error was not null, indicating an error. Error: 'invalid_request'. Error_Description (may be empty): 'AADSTS50194: Application 'sd-sd-sd-sd-fd'(ASPNET-Quickstart) is not configured as a multi-tenant application. Usage of the /common endpoint is not supported for such applications created after '10/15/2018'. Use a tenant-specific endpoint or configure the application to be multi-tenant. Trace ID: df-df-45ed-b605-dfg Correlation ID: f-f1ccd-fd-b8ff-df Timestamp: 2022-06-10 21:47:06Z'. Error_Uri (may be empty): 'error_uri is null'."

Upvotes: 0

Views: 217

Answers (1)

Tiny Wang
Tiny Wang

Reputation: 16029

Please change Authority = "https://login.microsoftonline.com/common/v2.0", to Authority = "https://login.microsoftonline.com/your_tenant_name/v2.0",

The error message indicated that you need to set the application you get from private static string appId = ConfigurationManager.AppSettings["ida:AppId"]; is not a multi-tenant azure ad application. So you have to set the tenant_name or tenant_id in your Authority url but not common.

Your tenant name may look like xxx.onmicrosoft.com, you can go to azure portal->azure active directory->app registration->your azure ad app->overview to get the tenant id.

enter image description here

Upvotes: 1

Related Questions