diff --git a/CommunityToolkit.Authentication.Msal/CommunityToolkit.Authentication.Msal.csproj b/CommunityToolkit.Authentication.Msal/CommunityToolkit.Authentication.Msal.csproj
index 050e3e8..7bfb3bd 100644
--- a/CommunityToolkit.Authentication.Msal/CommunityToolkit.Authentication.Msal.csproj
+++ b/CommunityToolkit.Authentication.Msal/CommunityToolkit.Authentication.Msal.csproj
@@ -14,6 +14,7 @@
+
diff --git a/CommunityToolkit.Authentication.Msal/MsalProvider.cs b/CommunityToolkit.Authentication.Msal/MsalProvider.cs
index b871901..419abdb 100644
--- a/CommunityToolkit.Authentication.Msal/MsalProvider.cs
+++ b/CommunityToolkit.Authentication.Msal/MsalProvider.cs
@@ -6,7 +6,9 @@
using System.Net.Http;
using System.Net.Http.Headers;
using System.Reflection;
+using System.Threading;
using System.Threading.Tasks;
+using Microsoft.Graph;
using Microsoft.Identity.Client;
namespace CommunityToolkit.Authentication
@@ -16,6 +18,8 @@ namespace CommunityToolkit.Authentication
///
public class MsalProvider : BaseProvider
{
+ private static readonly SemaphoreSlim SemaphoreSlim = new (1);
+
///
public override string CurrentAccountId => _account?.HomeAccountId?.Identifier;
@@ -47,7 +51,7 @@ public MsalProvider(string clientId, string[] scopes = null, string redirectUri
.WithClientVersion(Assembly.GetExecutingAssembly().GetName().Version.ToString())
.Build();
- Scopes = scopes ?? new string[] { string.Empty };
+ Scopes = scopes.Select(s => s.ToLower()).ToArray() ?? new string[] { string.Empty };
Client = client;
@@ -60,7 +64,23 @@ public MsalProvider(string clientId, string[] scopes = null, string redirectUri
///
public override async Task AuthenticateRequestAsync(HttpRequestMessage request)
{
- string token = await GetTokenAsync();
+ string token;
+
+ // Check if any specific scopes are being requested.
+ if (request.Properties.TryGetValue(nameof(GraphRequestContext), out object requestContextObj) &&
+ requestContextObj is GraphRequestContext requestContext &&
+ requestContext.MiddlewareOptions.TryGetValue(nameof(AuthenticationHandlerOption), out IMiddlewareOption optionsMiddleware) &&
+ optionsMiddleware is AuthenticationHandlerOption options &&
+ options.AuthenticationProviderOption?.Scopes != null && options.AuthenticationProviderOption.Scopes.Length > 0)
+ {
+ var withScopes = options.AuthenticationProviderOption.Scopes;
+ token = await this.GetTokenWithScopesAsync(withScopes);
+ }
+ else
+ {
+ token = await this.GetTokenAsync();
+ }
+
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);
}
@@ -119,42 +139,63 @@ public override async Task SignOutAsync()
}
///
- public override async Task GetTokenAsync(bool silentOnly = false)
+ public override Task GetTokenAsync(bool silentOnly = false)
{
- AuthenticationResult authResult = null;
+ return this.GetTokenWithScopesAsync(Scopes, silentOnly);
+ }
+
+ private async Task GetTokenWithScopesAsync(string[] scopes, bool silentOnly = false)
+ {
+ await SemaphoreSlim.WaitAsync();
+
try
{
- var account = _account ?? (await Client.GetAccountsAsync()).FirstOrDefault();
- if (account != null)
+ AuthenticationResult authResult = null;
+ try
{
- authResult = await Client.AcquireTokenSilent(Scopes, account).ExecuteAsync();
+ var account = _account ?? (await Client.GetAccountsAsync()).FirstOrDefault();
+ if (account != null)
+ {
+ authResult = await Client.AcquireTokenSilent(scopes, account).ExecuteAsync();
+ }
}
- }
- catch (MsalUiRequiredException)
- {
- }
- catch
- {
- // Unexpected exception
- // TODO: Send exception to a logger.
- }
-
- if (authResult == null && !silentOnly)
- {
- try
+ catch (MsalUiRequiredException)
{
- authResult = await Client.AcquireTokenInteractive(Scopes).WithPrompt(Prompt.SelectAccount).ExecuteAsync();
}
catch
{
// Unexpected exception
// TODO: Send exception to a logger.
}
- }
- _account = authResult?.Account;
+ if (authResult == null && !silentOnly)
+ {
+ try
+ {
+ if (_account != null)
+ {
+ authResult = await Client.AcquireTokenInteractive(scopes).WithPrompt(Prompt.NoPrompt).WithAccount(_account).ExecuteAsync();
+ }
+ else
+ {
+ authResult = await Client.AcquireTokenInteractive(scopes).WithPrompt(Prompt.NoPrompt).ExecuteAsync();
+ }
+ }
+ catch
+ {
+ // Unexpected exception
+ // TODO: Send exception to a logger.
+ }
+ }
+
+ _account = authResult?.Account;
- return authResult?.AccessToken;
+ return authResult?.AccessToken;
+ }
+ finally
+ {
+ SemaphoreSlim.Release();
+ }
}
}
}
diff --git a/CommunityToolkit.Authentication.Uwp/WindowsProvider.cs b/CommunityToolkit.Authentication.Uwp/WindowsProvider.cs
index a7864c8..223a443 100644
--- a/CommunityToolkit.Authentication.Uwp/WindowsProvider.cs
+++ b/CommunityToolkit.Authentication.Uwp/WindowsProvider.cs
@@ -6,6 +6,7 @@
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
+using System.Threading;
using System.Threading.Tasks;
using Windows.Networking.Connectivity;
using Windows.Security.Authentication.Web;
@@ -28,6 +29,8 @@ public class WindowsProvider : BaseProvider
///
public static string RedirectUri => string.Format("ms-appx-web://Microsoft.AAD.BrokerPlugIn/{0}", WebAuthenticationBroker.GetCurrentApplicationCallbackUri().Host.ToUpper());
+ private static readonly SemaphoreSlim SemaphoreSlim = new(1);
+
private const string AuthenticationHeaderScheme = "Bearer";
private const string GraphResourcePropertyKey = "resource";
private const string GraphResourcePropertyValue = "https://graph.microsoft.com";
@@ -181,18 +184,22 @@ public override async Task SignOutAsync()
///
public override async Task GetTokenAsync(bool silentOnly = false)
{
- var internetConnectionProfile = NetworkInformation.GetInternetConnectionProfile();
- if (internetConnectionProfile == null)
- {
- // We are not online, no token for you.
- // TODO: Is there anything special to do when we go offline?
- return null;
- }
+ await SemaphoreSlim.WaitAsync();
try
{
+ var internetConnectionProfile = NetworkInformation.GetInternetConnectionProfile();
+ if (internetConnectionProfile == null)
+ {
+ // We are not online, no token for you.
+ // TODO: Is there anything special to do when we go offline?
+ return null;
+ }
+
+ var scopes = _scopes;
+
// Attempt to authenticate silently.
- var authResult = await AuthenticateSilentAsync(_scopes);
+ var authResult = await AuthenticateSilentAsync(scopes);
// Authenticate with user interaction as appropriate.
if (authResult?.ResponseStatus != WebTokenRequestStatus.Success)
@@ -204,7 +211,7 @@ public override async Task GetTokenAsync(bool silentOnly = false)
}
// Attempt to authenticate interactively.
- authResult = await AuthenticateInteractiveAsync(_scopes);
+ authResult = await AuthenticateInteractiveAsync(scopes);
}
if (authResult?.ResponseStatus == WebTokenRequestStatus.Success)
@@ -232,9 +239,12 @@ public override async Task GetTokenAsync(bool silentOnly = false)
catch (Exception e)
{
// TODO: Log failure
- System.Diagnostics.Debug.WriteLine(e.Message);
throw e;
}
+ finally
+ {
+ SemaphoreSlim.Release();
+ }
}
///
diff --git a/CommunityToolkit.Graph.Uwp/Controls/PersonView/PersonView.cs b/CommunityToolkit.Graph.Uwp/Controls/PersonView/PersonView.cs
index 8771965..5f3deee 100644
--- a/CommunityToolkit.Graph.Uwp/Controls/PersonView/PersonView.cs
+++ b/CommunityToolkit.Graph.Uwp/Controls/PersonView/PersonView.cs
@@ -131,6 +131,11 @@ private async void LoadData()
else
{
LoadDefaultImage();
+
+ if (!string.IsNullOrWhiteSpace(UserId) || !string.IsNullOrWhiteSpace(PersonQuery))
+ {
+ PersonDetails = null;
+ }
}
}