In this lab, you will walk through building applications that connect with the Microsoft Graph API using multiple technologies.
- Build a .NET console application using Microsoft Graph
- Build a JavaScript application using Microsoft Graph
- Build an Azure Function using Microsoft Graph
- Build a mobile application with Xamarin using Microsoft Graph
This lab uses Visual Studio 2017. Exercise 4 requires Windows 10. It also requires an Azure Active Directory tenant and a user with administrative privileges.
Open the Visual Studio installer and enable the .NET desktop development, Mobile development with .NET, Azure development,and Universal Windows Platform development features. Make sure to update Visual Studio 2017 to the latest version, and update VSIX packages (Tools > Extensions and Updates).
In this exercise you will create a .NET console application from scratch using .NET Framework 4.7.0, the Microsoft Graph SDK, and the Microsoft Authentication Library (MSAL).
-
Navigate to the the Azure portal - App registrations to register your app. Login using a personal account (aka: Microsoft Account) or Work or School Account.
-
Select New registration. On the Register an application page, set the values as follows.
- Set Name to ConsoleDemo.
- Set Supported account types to Accounts in any organizational directory and personal Microsoft accounts.
- Leave Redirect URI empty.
- Choose Register.
-
On the ConsoleDemo page, copy the values of both the Application (client) ID and the Directory (tenant) ID. Save these two values, since you will need them later.
-
Select the Add a Redirect URI link. On the Redirect URIs page, locate the Suggested Redirect URIs for public clients (mobile, desktop) section. Select the URI that begins with
msaland the urn:ietf:wg:oauth:2.0:oob URI. -
Open the sample solution in Visual Studio and then open the Constants.cs file. Change the Tenant string to the Directory (tenant) ID value you copied earlier. Change the ClientIdForUserAuthn string to the Application (client) ID value.
-
In Visual Studio 2017, create a new Console Application project targeting .NET Framework 4.7.2.
-
Select Tools > NuGet Package Manager > Package Manager Console. In the console window, run the following commands:
Install-Package "Microsoft.Graph" Install-Package "Microsoft.Identity.Client" -version 2.7.1 Install-Package "System.Configuration.ConfigurationManager"
-
Edit the app.config file, and immediately before the
/configurationelement, add the following element replacing the value with the Application ID provided by the Application Registration Portal:<appSettings> <add key="clientId" value="YOUR CLIENT APPLICATION ID"/> </appSettings>
-
Add a class to the project named AuthenticationHelper.cs. This class will be responsible for authenticating using the Microsoft Authentication Library (MSAL), which is the Microsoft.Identity.Client package that we installed.
-
Replace the
usingstatement at the top of the file.using Microsoft.Graph; using Microsoft.Identity.Client; using System; using System.Configuration; using System.Diagnostics; using System.Linq; using System.Net.Http.Headers; using System.Threading.Tasks;
-
Replace the
classdeclaration with the following:public class AuthenticationHelper { // The Client ID is used by the application to uniquely identify itself to the v2.0 authentication endpoint. static string clientId = ConfigurationManager.AppSettings["clientId"].ToString(); public static string[] Scopes = { "User.Read" , "People.Read"}; public static PublicClientApplication IdentityClientApp = new PublicClientApplication(clientId); private static GraphServiceClient graphClient = null; // Get an access token for the given context and resourceId. An attempt is first made to // acquire the token silently. If that fails, then we try to acquire the token by prompting the user. public static GraphServiceClient GetAuthenticatedClient() { if (graphClient == null) { // Create Microsoft Graph client. try { graphClient = new GraphServiceClient( "https://graph.microsoft.com/v1.0", new DelegateAuthenticationProvider( async (requestMessage) => { var token = await GetTokenForUserAsync(); requestMessage.Headers.Authorization = new AuthenticationHeaderValue("bearer", token); })); return graphClient; } catch (Exception ex) { Debug.WriteLine("Could not create a graph client: " + ex.Message); } } return graphClient; } /// <summary> /// Get Token for User. /// </summary> /// <returns>Token for user.</returns> public static async Task<string> GetTokenForUserAsync() { AuthenticationResult authResult = null; try { authResult = await IdentityClientApp.AcquireTokenSilentAsync(Scopes, IdentityClientApp.Users.FirstOrDefault()); return authResult.AccessToken; } catch (MsalUiRequiredException ex) { // A MsalUiRequiredException happened on AcquireTokenSilentAsync. //This indicates you need to call AcquireTokenAsync to acquire a token authResult = await IdentityClientApp.AcquireTokenAsync(Scopes); return authResult.AccessToken; } } /// <summary> /// Signs the user out of the service. /// </summary> public static void SignOut() { foreach (var user in IdentityClientApp.Users) { IdentityClientApp.Remove(user); } graphClient = null; } }
The Microsoft Graph API makes it easy to obtain the currently logged in user's profile. This sample uses our AuthenticationHelper.cs class to obtain an authenticated client before accessing the /me endpoint alias.
-
Edit the
Program.csclass and replace the generated using statements with the following:using Microsoft.Graph; using Newtonsoft.Json.Linq; using System; using System.Diagnostics; using System.Net.Http; using System.Threading.Tasks;
-
To get the currently logged in user's profile information, add the following method:
/// <summary> /// Gets the currently logged in user's profile information /// </summary> public static async Task<User> GetMeAsync() { User currentUserObject = null; try { var graphClient = AuthenticationHelper.GetAuthenticatedClient(); currentUserObject = await graphClient.Me.Request().GetAsync(); Debug.WriteLine("Got user: " + currentUserObject.DisplayName); return currentUserObject; } catch (ServiceException e) { Debug.WriteLine("We could not get the current user: " + e.Error.Message); return null; } }
The Microsoft Graph API provides REST endpoints to access information and traverse relationships. One such endpoint is the me/people endpoint that provides information about people closely related to the current user. The following method demonstrates accessing the underlying System.Net.HttpClient to add an access token in the authorization header and to configure the URL for the request.
/// <summary>
/// Get people near me. Demonstrates using HttpClient to call the
/// Graph API.
/// </summary>
/// <returns></returns>
static async Task<string> GetPeopleNearMe()
{
try
{
//Get the Graph client
var graphClient = AuthenticationHelper.GetAuthenticatedClient();
var token = await AuthenticationHelper.GetTokenForUserAsync();
var request = new HttpRequestMessage(HttpMethod.Get, graphClient.BaseUrl + "/me/people");
request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
var response = await graphClient.HttpProvider.SendAsync(request);
var bodyContents = await response.Content.ReadAsStringAsync();
Debug.WriteLine(bodyContents);
return bodyContents;
}
catch (Exception e)
{
Debug.WriteLine("Could not get people: " + e.Message);
return null;
}
}The methods we created use the async/await pattern.
-
Create an async method named RunAsync with the following implementation:
static async Task RunAsync() { //Display information about the current user Console.WriteLine("Get My Profile"); Console.WriteLine(); var me = await GetMeAsync(); Console.WriteLine(me.DisplayName); Console.WriteLine("User:{0}\t\tEmail:{1}", me.DisplayName, me.Mail); Console.WriteLine(); //Display information about people near me Console.WriteLine("Get People Near Me"); var peopleJson = await GetPeopleNearMe(); dynamic people = JObject.Parse(peopleJson); if(null != people) { foreach(var p in people.value) { var personType = p.personType; Console.WriteLine("Object:{0}\t\t\t\tClass:{1}\t\tSubclass:{2}", p.displayName, personType["class"], personType.subclass); } } }
-
Update the main method to call the
RunAsync()method.static void Main(string[] args) { RunAsync().GetAwaiter().GetResult(); Console.WriteLine("Press any key to close"); Console.ReadKey(); }
-
Run the application and log in when prompted.
Note: The first time you run it, you will also be prompted to consent to the permissions the application is requesting.
-
After the application runs, you will see output similar to the output shown here.
There are many sample applications that demonstrate how to use the Microsoft Graph API and the Microsoft Graph SDK available online. This lab will walk you through creating a JavaScript application leveraging the QuickStart project template to quickly get started.
-
Navigate to the the Azure portal - App registrations to register your app. Login using a personal account (aka: Microsoft Account) or Work or School Account.
-
Select New registration. On the Register an application page, set the values as follows.
- Set Name to AngularDemo.
- Set Supported account types to Accounts in any organizational directory and personal Microsoft accounts.
- Under Redirect URI, set the first drop-down to
Weband set the value to http://localhost:8080
-
Choose Register. On the AngularDemo page, copy the value of the Application (client) ID and save it, you will need it in the next step.
-
Select Authentication under Manage. Locate the Implicit grant section and enable ID tokens. Choose Save.
-
Select Certificates & secrets under Manage. Select the New client secret button. Enter a value in Description and select one of the options for Expires and choose Add.
-
Copy the client secret value before you leave this page. You will need it in the next step.
[!IMPORTANT] This client secret is never shown again, so make sure you copy it now.
If you have an existing application that you have registered in the past, feel free to use that instead of creating a new registration.
You will use a QuickStart application to demonstrate working with AngularJS and the Azure AD v2 endpoint.
-
Download/clone the Microsoft Graph connect sample for AngularJS and open it in a code editor of your choice.
Note: This solution requires that you've installed Node.js. Please see the prerequisites in the sample project's README.md file for more information.
-
Edit the config.js file in public/scripts and replace the
clientIDplaceholder with the placeholder of your application. -
In a command prompt, change to the root directory and run the following:
npm install
-
Once installed, start the application by typing:
npm start
-
You may receive an error similar to "npm WARN" This failure might be due to the use of legacy binary 'node'. To work around this, install the
nodejs-legacy package.sudo apt-get install nodejs-legacy
-
The command window will show that the application is now listening on port 8080. Open a browser and type in http://localhost:8080. The application displays a dialog box and prompts you to connect.
-
Log in when prompted. Once logged in, grant the permissions requested by the application by selecting Accept. The application reads the current user's display name and enables you to send an email.
-
Inspect the code to see how this was accomplished. The application is hosted as a Node.js application that uses AngularJS. The
index.htmlpage defines the ng-app element and loads the files in the scripts directory as well as the mainController.js file.The graphHelper.js file contains the code that obtains the token and calls the Microsoft Graph API. An HTTP GET is issued to obtain the current user's profile, and an HTTP POST is issued to send email on behalf of the current user.
// Get the profile of the current user. me: function me() { return $http.get('https://graph.microsoft.com/v1.0/me'); }, // Send an email on behalf of the current user. sendMail: function sendMail(email) { return $http.post('https://graph.microsoft.com/v1.0/me/sendMail', { 'message' : email, 'saveToSentItems': true }); }
This exercise will build an Azure Function that runs on a scheduled basis to obtain all the users in the directory.
This solution will require an organizational account. An admin is required to provide consent. To facilitate this, you will start with an existing solution. Once you have tested that the app is successfully authenticating and retrieving users, you will implement an Azure Function that synchronizes users.
-
Clone or download the following project: Build a multi-tenant daemon with the Azure AD v2.0 endpoint
-
Navigate to the the Azure portal - App registrations to register your app. Login using a personal account (aka: Microsoft Account) or Work or School Account.
-
Select New registration. On the Register an application page, set the values as follows.
- Set Name to AzureSyncFunctionDemo.
- Set Supported account types to Accounts in any organizational directory and personal Microsoft accounts.
- Under Redirect URI, set the first drop-down to
Weband set the value to https://localhost:44316/
-
Choose Register. On the AzureSyncFunctionDemo page, copy the value of the Application (client) ID and save it, you will need it in the next step.
-
Select Authentication under Manage. Locate the Implicit grant section and enable ID tokens. Choose Save.
-
Select Certificates & secrets under Manage. Select the New client secret button. Enter a value in Description and select one of the options for Expires and choose Add.
-
Copy the client secret value before you leave this page. You will need it in the next step.
[!IMPORTANT] This client secret is never shown again, so make sure you copy it now.
-
In the list of pages for the app, select API permissions
- Click the Add a permission button and then,
- Ensure that the Microsoft APIs tab is selected
- In the Commonly used Microsoft APIs section, click on Microsoft Graph
- In the Delegated permissions section, ensure that the right permissions are checked. Use the search box if necessary.
- User.Read.All
- Select the Add permissions button
In order to use the v2.0 admin consent endpoint, you'll need to declare the application permissions your app will use ahead of time. While still in the registration portal,
- Locate the API Permissions section on your app registration.
- Under Add Permission, then Delegated Permissions select the
User.Read.Allpermission. - Be sure to click on Add permissions
-
Start the application called UserSync. Sign in as an administrator in your Azure AD tenant. If you don't have an Azure AD tenant for testing, you can follow these instructions to get one.
-
When the app loads, select the Get Started button.
-
On the next page, select Sign In. The app will ask you for permission to sign you in & read your user profile. This allows the application to ensure that you are a business user. The application will then try to sync a list of users from your Azure AD tenant via the Microsoft Graph. If it is unable to do so, it asks you (the tenant administrator) to connect your tenant to the application.
-
The application will ask for permission to read the list of users in your tenant. When you grant the permission, the application is able to query for users at any point. You can verify this by selecting the Sync Users button on the users page to refresh the list of users. Try adding or removing a user and re-syncing the list but note that it only syncs the first page of users.
Note: There is approximately a 20 minute data replication delay between the time when an application is granted admin consent and when the data can successfully synchronize. For more information, read this issue.
Visual Studio 2017 provides new tooling to simplify the creation of Azure Functions while enabling local debugging.
-
Under the Visual C#/Cloud node in the tree, choose the Azure Functions project template.
Note: For more details on creating Azure Functions using Visual Studio, see Azure Functions tools for Visual Studio.
-
Select Timer trigger and change the schedule to the following format:
*/30 * * * * * -
In the NuGet Package Manager Console, run the following command to install the required packages.
Install-Package "Microsoft.Graph" Install-Package "Microsoft.Identity.Client" -version 1.1.4-preview0002
-
Edit the local.settings.json file and add the following items to use while debugging locally.
clientId: The app ID of the registered application with AADclientSecret: The secret key of the registered application with AADtenantId: The tenant ID of the AAD directory. You can retrieve this value from your Microsoft Azure portal. Select ? and then select show diagnostics.authorityFormat: https://login.microsoftonline.com/{0}/v2.0replyUri: https://localhost:44316/
Note: AzureWebJobsStorage and AzureWebJobsDashboard will already be set with
UserDevelopmentStorage=truebecause you chose Storage Emulator as the Storage Account during project creation. -
Refer to the following to verify settings:
{ "IsEncrypted": false, "Values": { "AzureWebJobsStorage": "UseDevelopmentStorage=true", "AzureWebJobsDashboard": "UseDevelopmentStorage=true", "clientId": "b6299aea-4b9e-499f-a590-e2e29c6990e5", "clientSecret": "gb9p9w9Z9A9V9#9v94929!$", "tenantId": "9a9f949f-79b9-469b-b995-b49fe9ad967d", "authorityFormat": "https://login.microsoftonline.com/{0}/v2.0", "replyUri": "https://localhost:44316", "FUNCTIONS_WORKER_RUNTIME": "dotnet" } } -
Add a class named
MsGraphUser.csto the project with the following contents:using System.Collections.Generic; using Newtonsoft.Json; namespace AzureSyncFunction { public class MsGraphUser { [JsonProperty(PropertyName = "@odata.type")] public string odataType { get; set; } [JsonProperty(PropertyName = "@odata.id")] public string odataId { get; set; } public List<string> businessPhones { get; set; } public string displayName { get; set; } public string givenName { get; set; } public string jobTitle { get; set; } public string mail { get; set; } public string mobilePhone { get; set; } public string officeLocation { get; set; } public string preferredLanguage { get; set; } public string surname { get; set; } public string userPrincipalName { get; set; } public string id { get; set; } } public class MsGraphUserListResponse { [JsonProperty(PropertyName = "@odata.context")] public string context { get; set; } public List<MsGraphUser> value { get; set; } } }
-
Rename
Function1.cstoUserSync.csand replace the contents of the function class with the following:using System; using Microsoft.Azure.WebJobs; using Microsoft.Extensions.Logging; using System.Collections.Concurrent; using System.Collections.Generic; using System.Net.Http; using System.Net.Http.Headers; using Microsoft.Identity.Client; using Newtonsoft.Json; namespace AzureSyncFunction { public static class UserSync { private static string msGraphScope = "https://graph.microsoft.com/.default"; private static string msGraphQuery = "https://graph.microsoft.com/v1.0/users"; private static ConcurrentDictionary<string, List<MsGraphUser>> usersByTenant = new ConcurrentDictionary<string, List<MsGraphUser>>(); [FunctionName("UserSync")] public static void Run([TimerTrigger("*/30 * * * * *")]TimerInfo myTimer, ILogger log, ExecutionContext context) { log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}"); try { string clientId = Environment.GetEnvironmentVariable("clientId"); string clientSecret = Environment.GetEnvironmentVariable("clientSecret"); string tenantId = Environment.GetEnvironmentVariable("tenantId"); string authorityFormat = Environment.GetEnvironmentVariable("authorityFormat"); string replyUri = Environment.GetEnvironmentVariable("authorityFormat"); ConfidentialClientApplication daemonClient = new ConfidentialClientApplication(clientId, String.Format(authorityFormat, tenantId), replyUri, new ClientCredential(clientSecret), null, new TokenCache()); AuthenticationResult authResult = daemonClient.AcquireTokenForClientAsync(new[] { msGraphScope }).GetAwaiter().GetResult(); // Query for list of users in the tenant HttpClient client = new HttpClient(); HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, msGraphQuery); request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", authResult.AccessToken); HttpResponseMessage response = client.SendAsync(request).GetAwaiter().GetResult(); // If the token we used was insufficient to make the query, drop the token from the cache. // The Users page of the website will show a message to the user instructing them to grant // permissions to the app (see User/Index.cshtml). if (response.StatusCode == System.Net.HttpStatusCode.Forbidden) { // BUG: Here, we should clear MSAL's app token cache to ensure that on a subsequent call // to SyncController, MSAL does not return the same access token that resulted in this 403. // By clearing the cache, MSAL will be forced to retrieve a new access token from AAD, // which will contain the most up-to-date set of permissions granted to the app. Since MSAL // currently does not provide a way to clear the app token cache, we have commented this line // out. Thankfully, since this app uses the default in-memory app token cache, the app still // works correctly, since the in-memory cache is not persistent across calls to SyncController // anyway. If you build a persistent app token cache for MSAL, you should make sure to clear // it at this point in the code. // //daemonClient.AppTokenCache.Clear(Startup.clientId); log.LogError("Unable to issue query: Received " + response.StatusCode + " in Run method"); } if (!response.IsSuccessStatusCode) { log.LogError("Unable to issue query: Received " + response.StatusCode + " in Run method"); } // Record users in the data store (note that this only records the first page of users) string json = response.Content.ReadAsStringAsync().GetAwaiter().GetResult(); MsGraphUserListResponse users = JsonConvert.DeserializeObject<MsGraphUserListResponse>(json); usersByTenant[tenantId] = users.value; log.LogInformation("Successfully synchronized " + users.value.Count + " users!"); } catch (Exception oops) { log.LogError(oops.Message, oops, "AzureSyncFunction.UserSync.Run"); } } } }
-
Now that the project is coded and settings are configured, run the Azure Function project locally. A command window appears and provides output from the running function.
Note: you will need the Microsoft Azure Storage Emulator running. You can find it in your start menu. For more information see Configuring and using the storage emulator with Visual Studio
-
When the timer fires once every 30 seconds, the display will show the successful execution of the Azure Function.
-
Right-click the Azure Function project and choose Publish.
-
Select the Azure Function App. Select Create New and select OK.
-
Choose your Azure subscription, a resource group, an app service plan, and a storage account and then select Create. The function is published to your Azure subscription.
-
The local configuration settings are not published to the Azure Function. Open the Azure Function and choose Application Settings. Provide the same key and value pairs that you used within your local debug session.
-
Select the Monitor node to monitor the Azure Function as it runs every 30 seconds. In the Logs window, verify that you are successfully synchronizing users.
Note: If your Azure Function will not execute you may need to modify the Application Setting FUNCTIONS_EXTENSION_VERSION to beta
In this exercise, you will work through building an application using Xamarin.Forms. You must be running Windows 10 for this lab to work. This demo only walks through creating a UWP application. For more information on creating Android and iOS projects using Xamarin.Forms that target Microsoft Graph API, see the Xamarin CSharp connect sample on GitHub.
- Navigate to the Azure portal - App registrations page.
- Select New registration.
- When the Register an application page appears, enter your application's registration information:
- In the Name section, enter a meaningful application name that will be displayed to users of the app, for example
XamarinApp Sample. - In the Supported account types section, select Accounts in any organizational directory.
- In the Name section, enter a meaningful application name that will be displayed to users of the app, for example
- Select Register to create the application.
- On the app Overview page, find the Application (client) ID value and record it for later. You'll need it to configure the Visual Studio configuration file for this project.
- In the list of pages for the app, select Manifest, and:
- In the manifest editor, set the
allowPublicClientproperty to true - Select Save in the bar above the manifest editor.
- In the manifest editor, set the
- In the list of pages for the app, select API permissions
- Click the Add a permission button and then,
- Ensure that the Microsoft APIs tab is selected
- In the Commonly used Microsoft APIs section, click on Microsoft Graph
- In the Delegated permissions section, ensure that the right permissions are checked. Use the search box if necessary.
- User.Read
- Select the Add permissions button
-
Open Visual Studio 2017. Create a new Cross-Platform/Mobile App (Xamarin.Forms) project.
-
When prompted for the template type, choose Blank app. Unselect iOS and Android from platform and choose .NET Standard as the code sharing strategy.
-
Two projects were created because you unchecked iOS and Android:
[App1]: a .NET standard class library project where most logic will reside[App1.UWP]: a Universal Windows Platform project containing Windows display logic
Note: This lab only walks through creating a UWP application using Xamarin.Forms. For more information on creating Android and iOS projects using Xamarin.Forms that target Microsoft Graph API, see the Xamarin CSharp connect sample on GitHub.
-
In Visual Studio, go to Tools > NuGet Package Manager > Package Manager Console. Install the
Microsoft.Identity.Clientpackage to all projects, and install theNewtonsoft.Jsonpackage to the portable class library project. ReplaceApp1with the name you gave your solution.Install-Package Microsoft.Identity.Client -ProjectName App1 -version 1.1.4-preview0002 Install-Package Newtonsoft.Json -ProjectName App1 Install-Package Microsoft.Identity.Client -ProjectName App1.UWP -version 1.1.4-preview0002
-
Edit the app.xaml.cs file in the portable class library project. Replace the
usingsection with the following:using Xamarin.Forms; using Xamarin.Forms.Xaml; using Microsoft.Identity.Client;
-
Replace the body of the class with the following:
public partial class App : Application { public static PublicClientApplication PCA = null; public static string ClientID = "YOUR_CLIENT_ID"; public static string[] Scopes = { "User.Read" }; public static string Username = string.Empty; public static UIParent UiParent = null; public App() { InitializeComponent(); // default redirectURI; each platform specific project will have to override it with its own PCA = new PublicClientApplication(ClientID); MainPage = new XamarinApp.MainPage(); } protected override void OnStart() { // Handle when your app starts } protected override void OnSleep() { // Handle when your app sleeps } protected override void OnResume() { // Handle when your app resumes } }
-
Replace the
YOUR_CLIENT_IDplaceholder with the App ID that was generated when the application was registered. -
Edit the MainPage.xaml file. Replace the generated
StackLayoutcontrol with the following:<StackLayout> <Label Text="MSAL Xamarin Forms Sample" VerticalOptions="Start" HorizontalTextAlignment="Center" HorizontalOptions="FillAndExpand" /> <BoxView Color="Transparent" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" /> <StackLayout x:Name="slUser" IsVisible="False" Padding="5,10"> <StackLayout Orientation="Horizontal"> <Label Text="DisplayName " FontAttributes="Bold" /> <Label x:Name="lblDisplayName" /> </StackLayout> <StackLayout Orientation="Horizontal"> <Label Text="GivenName " FontAttributes="Bold" /> <Label x:Name="lblGivenName" /> </StackLayout> <StackLayout Orientation="Horizontal"> <Label Text="Surname " FontAttributes="Bold" /> <Label x:Name="lblSurname" /> </StackLayout> <StackLayout Orientation="Horizontal"> <Label Text="Id " FontAttributes="Bold" /> <Label x:Name="lblId" /> </StackLayout> <StackLayout Orientation="Horizontal"> <Label Text="UserPrincipalName " FontAttributes="Bold" /> <Label x:Name="lblUserPrincipalName" /> </StackLayout> </StackLayout> <BoxView Color="Transparent" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" /> <Button x:Name="btnSignInSignOut" Text="Sign in" Clicked="OnSignInSignOut" VerticalOptions="End" HorizontalOptions="FillAndExpand"/> </StackLayout>
-
Edit the MainPage.xaml.cs file. Replace the
usingstatements with the following:using System; using System.Linq; using Xamarin.Forms; using Microsoft.Identity.Client; using Newtonsoft.Json.Linq; using System.Net.Http;
-
Add the following methods to the
MainPage.xaml.csclass:protected override async void OnAppearing() { // let's see if we have a user already try { AuthenticationResult ar = await App.PCA.AcquireTokenSilentAsync(App.Scopes, App.PCA.Users.FirstOrDefault()); RefreshUserData(ar.AccessToken); btnSignInSignOut.Text = "Sign out"; } catch { // doesn't matter, we go in interactive more btnSignInSignOut.Text = "Sign in"; } } async void OnSignInSignOut(object sender, EventArgs e) { try { if (btnSignInSignOut.Text == "Sign in") { AuthenticationResult ar = await App.PCA.AcquireTokenAsync(App.Scopes, App.UiParent); RefreshUserData(ar.AccessToken); btnSignInSignOut.Text = "Sign out"; } else { foreach (var user in App.PCA.Users) { App.PCA.Remove(user); } slUser.IsVisible = false; btnSignInSignOut.Text = "Sign in"; } } catch (Exception ee) { await DisplayAlert("Something went wrong signing in/out", ee.Message, "Dismiss"); } } public async void RefreshUserData(string token) { //get data from API HttpClient client = new HttpClient(); HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me"); message.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", token); HttpResponseMessage response = await client.SendAsync(message); string responseString = await response.Content.ReadAsStringAsync(); if (response.IsSuccessStatusCode) { JObject user = JObject.Parse(responseString); slUser.IsVisible = true; lblDisplayName.Text = user["displayName"].ToString(); lblGivenName.Text = user["givenName"].ToString(); lblId.Text = user["id"].ToString(); lblSurname.Text = user["surname"].ToString(); lblUserPrincipalName.Text = user["userPrincipalName"].ToString(); // just in case btnSignInSignOut.Text = "Sign out"; } else { await DisplayAlert("Something went wrong with the API call", responseString, "Dismiss"); } }
-
To verify the application's behavior, start debugging. In the debug menu, change the platform to x64 (or x86 if your machine isn't 64-bit) and change the target to Local Machine and select the play button to start debugging.
-
When the app loads, select the Sign In button at the bottom of the screen. After signing in, the current user's profile information is displayed.
Note: You can sign in using an organizational account such as a work or school account, or you can sign in with a Microsoft account such as a Live.com, Outlook.com, or Hotmail.com personal email address.


















