dimanche 1 novembre 2020

Microsoft Login for UWP on Windows 10 apps and Xbox One using Microsoft Graph [2020] [C#]

We are going to go over how to implement Microsoft login inside your application on Windows 10 apps and Xbox One apps.


We used to use the old login endpoint login.microsoft.com to login our users and today we have update our app to use the new graph endpoint from Microsoft you can download the nuget package called Microsoft.Graph and also Microsoft.Identity.Client.


Microsoft has greatly improved how you can login to its API compared to how I used to login or it might have been me that was not doing the best way.

Next we will try to login a user using the MS documentation.  We are using simple scopes for our login "user.read" and our ClientId was registered in our Azure portal.

The login code:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
private async void CallMsGraphLogin()
{
	try
	{
		// Sign-in user using MSAL and obtain an access token for MS Graph
		GraphServiceClient graphClient = await SignInAndInitializeGraphServiceClient(scopes);

		// Call the /me endpoint of Graph
		Microsoft.Graph.User graphUser = await graphClient.Me.Request().GetAsync();

		string token = await SignInUserAndGetTokenUsingMSAL(scopes);
		 
		MsTokenReceived?.Invoke(token);
	}
	catch (MsalException msalEx)
	{
		MsErrorLoginReceived?.Invoke($"Error Acquiring Token:{System.Environment.NewLine}{msalEx}");
		//await DisplayMessageAsync($"Error Acquiring Token:{System.Environment.NewLine}{msalEx}");
	}
	catch (Exception ex)
	{
		MsErrorLoginReceived?.Invoke($"Error Acquiring Token Silently:{System.Environment.NewLine}{ex}");
		return;
	}
}


The app will register to the MS Graph API and will ask the user to login, which will generate the Microsoft login window.





We will not go over the methods call SignInUserAndGetTokenUsingMSAL and SignInAndInitializeGraphServiceClient as I would be saying the same thing as the Microsoft documentation which can be found here.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
private static async Task<string> SignInUserAndGetTokenUsingMSAL(string[] scopes)
{
	// Initialize the MSAL library by building a public client application
	PublicClientApp = PublicClientApplicationBuilder.Create(ClientId)
		.WithAuthority(Authority)
		.WithUseCorporateNetwork(false)
		.WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient")
		 .WithLogging((level, message, containsPii) =>
		 {
			 Debug.WriteLine($"MSAL: {level} {message} ");
		 }, LogLevel.Warning, enablePiiLogging: false, enableDefaultPlatformLogging: true)
		.Build();

	// It's good practice to not do work on the UI thread, so use ConfigureAwait(false) whenever possible.
	IEnumerable<IAccount> accounts = await PublicClientApp.GetAccountsAsync().ConfigureAwait(false);
	IAccount firstAccount = accounts.FirstOrDefault();

	try
	{
		authResult = await PublicClientApp.AcquireTokenSilent(scopes, firstAccount)
										  .ExecuteAsync();
	}
	catch (MsalUiRequiredException ex)
	{
		// A MsalUiRequiredException happened on AcquireTokenSilentAsync. This indicates you need to call AcquireTokenAsync to acquire a token
		Debug.WriteLine($"MsalUiRequiredException: {ex.Message}");

		authResult = await PublicClientApp.AcquireTokenInteractive(scopes)
										  .ExecuteAsync()
										  .ConfigureAwait(false);

	}
	return authResult.AccessToken;
}

/// <summary>
/// Sign in user using MSAL and obtain a token for MS Graph
/// </summary>
/// <returns>GraphServiceClient</returns>
private async static Task<GraphServiceClient> SignInAndInitializeGraphServiceClient(string[] scopes)
{
	GraphServiceClient graphClient = new GraphServiceClient(MSGraphURL,
		new DelegateAuthenticationProvider(async (requestMessage) =>
		{
			requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", await SignInUserAndGetTokenUsingMSAL(scopes));
		}));

	return await Task.FromResult(graphClient);
}