/// <summary> /// Obtain an access token using MSAL running inside the current process. /// </summary> private async Task <JsonWebToken> GetAccessTokenInProcAsync(string authority, string clientId, Uri redirectUri, string[] scopes, string userName) { IPublicClientApplication app = await CreatePublicClientApplicationAsync(authority, clientId, redirectUri); AuthenticationResult result = null; // Try silent authentication first if we know about an existing user if (!string.IsNullOrWhiteSpace(userName)) { result = await GetAccessTokenSilentlyAsync(app, scopes, userName); } // // If we failed to acquire an AT silently (either because we don't have an existing user, or the user's RT has expired) // we need to prompt the user for credentials. // // Depending on the current platform and session type we try to show the most appropriate authentication interface: // // On .NET Framework MSAL supports the WinForms based 'embedded' webview UI. For Windows + .NET Framework this is the // best and natural experience. // // On other runtimes (e.g., .NET Core) MSAL only supports the system webview flow (launch the user's browser), // and the device-code flows. // // Note: .NET Core 3 allows using WinForms when run on Windows but MSAL does not yet support this. // // The system webview flow requires that the redirect URI is a loopback address, and that we are in an interactive session. // // The device code flow has no limitations other than a way to communicate to the user the code required to authenticate. // if (result is null) { #if NETFRAMEWORK // If we're in an interactive session and on .NET Framework, let MSAL show the WinForms-based embeded UI if (PlatformUtils.IsInteractiveSession()) { result = await app.AcquireTokenInteractive(scopes) .WithPrompt(Prompt.SelectAccount) .WithUseEmbeddedWebView(true) .ExecuteAsync(); } #elif NETSTANDARD // MSAL requires the application redirect URI is a loopback address to use the System WebView if (PlatformUtils.IsInteractiveSession() && app.IsSystemWebViewAvailable && redirectUri.IsLoopback) { result = await app.AcquireTokenInteractive(scopes) .WithPrompt(Prompt.SelectAccount) .WithSystemWebViewOptions(GetSystemWebViewOptions()) .ExecuteAsync(); } #endif // If we do not have a way to show a GUI, use device code flow over the TTY else { EnsureTerminalPromptsEnabled(); result = await app.AcquireTokenWithDeviceCode(scopes, ShowDeviceCodeInTty).ExecuteAsync(); } } return(new JsonWebToken(result.AccessToken)); }