This repository has been archived by the owner on Apr 10, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 10
/
MainPage.xaml.cs
195 lines (171 loc) · 8.53 KB
/
MainPage.xaml.cs
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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
using Microsoft.Graph;
using Microsoft.Identity.Client;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409
namespace Native_UWP_V2
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainPage : Page
{
//Set the scope for API call to user.read
private string[] scopes = new string[] { "user.read" };
// Below are the clientId (Application Id) of your app registration and the tenant information.
// You have to replace:
// - the content of ClientID with the Application Id for your app registration
// - The content of Tenant by the information about the accounts allowed to sign-in in your application:
// - For Work or School account in your org, use your tenant ID, or domain
// - for any Work or School accounts, use organizations
// - for any Work or School accounts, or Microsoft personal account, use common
// - for Microsoft Personal account, use consumers
private const string ClientId = "4a1aa1d5-c567-49d0-ad0b-cd957a47f842";
private const string Tenant = "common"; // Alternatively "[Enter your tenant, as obtained from the azure portal, e.g. kko365.onmicrosoft.com]"
private const string Authority = "https://login.microsoftonline.com/" + Tenant;
// The MSAL Public client app
private static IPublicClientApplication PublicClientApp;
private static string MSGraphURL = "https://graph.microsoft.com/v1.0/";
private static AuthenticationResult authResult;
public MainPage()
{
this.InitializeComponent();
}
/// <summary>
/// Call AcquireTokenAsync - to acquire a token requiring user to sign-in
/// </summary>
private async void CallGraphButton_Click(object sender, RoutedEventArgs e)
{
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
User graphUser = await graphClient.Me.Request().GetAsync();
// Go back to the UI thread to make changes to the UI
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
ResultText.Text = "Display Name: " + graphUser.DisplayName + "\nBusiness Phone: " + graphUser.BusinessPhones.FirstOrDefault()
+ "\nGiven Name: " + graphUser.GivenName + "\nid: " + graphUser.Id
+ "\nUser Principal Name: " + graphUser.UserPrincipalName;
DisplayBasicTokenInfo(authResult);
this.SignOutButton.Visibility = Visibility.Visible;
});
}
catch (MsalException msalEx)
{
await DisplayMessageAsync($"Error Acquiring Token:{System.Environment.NewLine}{msalEx}");
}
catch (Exception ex)
{
await DisplayMessageAsync($"Error Acquiring Token Silently:{System.Environment.NewLine}{ex}");
return;
}
}
/// <summary>
/// Signs in the user and obtains an Access token for MS Graph
/// </summary>
/// <param name="scopes"></param>
/// <returns> Access Token</returns>
private static async Task<string> SignInUserAndGetTokenUsingMSAL(string[] scopes)
{
// returns smth like S-1-15-2-2601115387-131721061-1180486061-1362788748-631273777-3164314714-2766189824
string sid = Windows.Security.Authentication.Web.WebAuthenticationBroker.GetCurrentApplicationCallbackUri().Host.ToUpper();
// This is redirect uri you need to register in the app registration portal. The app config does not need it.
string redirectUri = $"ms-appx-web://microsoft.aad.brokerplugin/{sid}";
// Initialize the MSAL library by building a public client application
PublicClientApp = PublicClientApplicationBuilder.Create(ClientId)
.WithAuthority(Authority)
.WithBroker(true)
.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();
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}");
// Must be called from UI thread
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);
}
/// <summary>
/// Sign out the current user
/// </summary>
private async void SignOutButton_Click(object sender, RoutedEventArgs e)
{
IEnumerable<IAccount> accounts = await PublicClientApp.GetAccountsAsync().ConfigureAwait(false);
IAccount firstAccount = accounts.FirstOrDefault();
try
{
await PublicClientApp.RemoveAsync(firstAccount).ConfigureAwait(false);
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
{
ResultText.Text = "User has signed-out";
this.CallGraphButton.Visibility = Visibility.Visible;
this.SignOutButton.Visibility = Visibility.Collapsed;
});
}
catch (MsalException ex)
{
ResultText.Text = $"Error signing-out user: {ex.Message}";
}
}
/// <summary>
/// Display basic information contained in the token. Needs to be called from the UI thead.
/// </summary>
private void DisplayBasicTokenInfo(AuthenticationResult authResult)
{
TokenInfoText.Text = "";
if (authResult != null)
{
TokenInfoText.Text += $"User Name: {authResult.Account.Username}" + Environment.NewLine;
TokenInfoText.Text += $"Token Expires: {authResult.ExpiresOn.ToLocalTime()}" + Environment.NewLine;
}
}
/// <summary>
/// Displays a message in the ResultText. Can be called from any thread.
/// </summary>
private async Task DisplayMessageAsync(string message)
{
await Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal,
() =>
{
ResultText.Text = message;
});
}
}
}