Call the Microsoft Graph API from a Windows Desktop app

This guide demonstrates how a native Windows Desktop .NET (XAML) application uses an access token to call the Microsoft Graph API. The app can also access other APIs that require access tokens from a Microsoft identity platform for developers v2.0 endpoint. This platform was formerly named Azure AD.

When you've completed the guide, your application will be able to call a protected API that uses personal accounts (including outlook.com, live.com, and others). The application will also use work and school accounts from any company or organization that uses Azure Active Directory.

Note

The guide requires Visual Studio 2015 Update 3, Visual Studio 2017, or Visual Studio 2019. Don’t have any of these versions? Download Visual Studio 2019 for free.

How the sample app generated by this guide works

Shows how the sample app generated by this tutorial works

The sample application that you create with this guide enables a Windows Desktop application that queries the Microsoft Graph API or a Web API that accepts tokens from a Microsoft identity-platform endpoint. For this scenario, you add a token to HTTP requests via the Authorization header. Microsoft Authentication Library (MSAL) handles token acquisition and renewal.

Handling token acquisition for accessing protected Web APIs

After the user is authenticated, the sample application receives a token you can use to query Microsoft Graph API or a Web API that's secured by Microsoft identity platform for developers.

APIs such as Microsoft Graph require a token to allow access to specific resources. For example, a token is required to read a user’s profile, access a user’s calendar, or send email. Your application can request an access token by using MSAL to access these resources by specifying API scopes. This access token is then added to the HTTP Authorization header for every call that's made against the protected resource.

MSAL manages caching and refreshing access tokens for you, so that your application doesn't need to.

NuGet packages

This guide uses the following NuGet packages:

Library Description
Microsoft.Identity.Client Microsoft Authentication Library (MSAL.NET)

Set up your project

In this section you create a new project to demonstrate how to integrate a Windows Desktop .NET application (XAML) with Sign-In with Microsoft so that the application can query Web APIs that require a token.

The application that you create with this guide displays a button that's used to call a graph, an area to show the results on the screen, and a sign-out button.

Note

Prefer to download this sample's Visual Studio project instead? Download a project, and skip to the Configuration step to configure the code sample before you execute it.

To create your application, do the following:

  1. In Visual Studio, select File > New > Project.
  2. Under Templates, select Visual C#.
  3. Select WPF App (.NET Framework), depending on the version of Visual Studio version you're using.

Add MSAL to your project

  1. In Visual Studio, select Tools > NuGet Package Manager> Package Manager Console.

  2. In the Package Manager Console window, paste the following Azure PowerShell command:

    Install-Package Microsoft.Identity.Client -Pre
    

    Note

    This command installs Microsoft Authentication Library. MSAL handles acquiring, caching, and refreshing user tokens that are used to access the APIs that are protected by Azure Active Directory v2.0

Add the code to initialize MSAL

In this step, you create a class to handle interaction with MSAL, such as handling of tokens.

  1. Open the App.xaml.cs file, and then add the reference for MSAL to the class:

    using Microsoft.Identity.Client;
    
  2. Update the app class to the following:

    public partial class App : Application
    {
        static App()
        {
            _clientApp = PublicClientApplicationBuilder.Create(ClientId)
                .WithAuthority(AzureCloudInstance.AzurePublic, Tenant)
                .Build();
        }
    
        // 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 static string ClientId = "0b8b0665-bc13-4fdc-bd72-e0227b9fc011";
    
        private static string Tenant = "common";
    
        private static IPublicClientApplication _clientApp ;
    
        public static IPublicClientApplication PublicClientApp { get { return _clientApp; } }
    }
    

Create the application UI

This section shows how an application can query a protected back-end server such as Microsoft Graph.

A MainWindow.xaml file should automatically be created as a part of your project template. Open this file, and then replace your application's <Grid> node with the following code:

<Grid>
    <StackPanel Background="Azure">
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
            <Button x:Name="CallGraphButton" Content="Call Microsoft Graph API" HorizontalAlignment="Right" Padding="5" Click="CallGraphButton_Click" Margin="5" FontFamily="Segoe Ui"/>
            <Button x:Name="SignOutButton" Content="Sign-Out" HorizontalAlignment="Right" Padding="5" Click="SignOutButton_Click" Margin="5" Visibility="Collapsed" FontFamily="Segoe Ui"/>
        </StackPanel>
        <Label Content="API Call Results" Margin="0,0,0,-5" FontFamily="Segoe Ui" />
        <TextBox x:Name="ResultText" TextWrapping="Wrap" MinHeight="120" Margin="5" FontFamily="Segoe Ui"/>
        <Label Content="Token Info" Margin="0,0,0,-5" FontFamily="Segoe Ui" />
        <TextBox x:Name="TokenInfoText" TextWrapping="Wrap" MinHeight="70" Margin="5" FontFamily="Segoe Ui"/>
    </StackPanel>
</Grid>

Use MSAL to get a token for the Microsoft Graph API

In this section, you use MSAL to get a token for the Microsoft Graph API.

  1. In the MainWindow.xaml.cs file, add the reference for MSAL to the class:

    using Microsoft.Identity.Client;
    
  2. Replace the MainWindow class code with the following:

    public partial class MainWindow : Window
    {
        //Set the API Endpoint to Graph 'me' endpoint
        string graphAPIEndpoint = "https://graph.microsoft.com/v1.0/me";
    
        //Set the scope for API call to user.read
        string[] scopes = new string[] { "user.read" };
    
    
        public MainWindow()
        {
            InitializeComponent();
        }
    
      /// <summary>
        /// Call AcquireToken - to acquire a token requiring user to sign-in
        /// </summary>
        private async void CallGraphButton_Click(object sender, RoutedEventArgs e)
        {
            AuthenticationResult authResult = null;
            var app = App.PublicClientApp;
            ResultText.Text = string.Empty;
            TokenInfoText.Text = string.Empty;
    
            var accounts = await app.GetAccountsAsync();
            var firstAccount = accounts.FirstOrDefault();
    
            try
            {
                authResult = await app.AcquireTokenSilent(scopes, firstAccount)
                    .ExecuteAsync();
            }
            catch (MsalUiRequiredException ex)
            {
                // A MsalUiRequiredException happened on AcquireTokenSilent.
                // This indicates you need to call AcquireTokenInteractive to acquire a token
                System.Diagnostics.Debug.WriteLine($"MsalUiRequiredException: {ex.Message}");
    
                try
                {
                    authResult = await app.AcquireTokenInteractive(scopes)
                        .WithAccount(accounts.FirstOrDefault())
                        .WithPrompt(Prompt.SelectAccount)
                        .ExecuteAsync();
                }
                catch (MsalException msalex)
                {
                    ResultText.Text = $"Error Acquiring Token:{System.Environment.NewLine}{msalex}";
                }
            }
            catch (Exception ex)
            {
                ResultText.Text = $"Error Acquiring Token Silently:{System.Environment.NewLine}{ex}";
                return;
            }
    
            if (authResult != null)
            {
                ResultText.Text = await GetHttpContentWithToken(graphAPIEndpoint, authResult.AccessToken);
                DisplayBasicTokenInfo(authResult);
                this.SignOutButton.Visibility = Visibility.Visible;
            }
        }
    

More information

Get a user token interactively

Calling the AcquireTokenInteractive method results in a window that prompts users to sign in. Applications usually require users to sign in interactively the first time they need to access a protected resource. They might also need to sign in when a silent operation to acquire a token fails (for example, when a user’s password is expired).

Get a user token silently

The AcquireTokenSilent method handles token acquisitions and renewals without any user interaction. After AcquireTokenInteractive is executed for the first time, AcquireTokenSilent is the usual method to use to obtain tokens that access protected resources for subsequent calls, because calls to request or renew tokens are made silently.

Eventually, the AcquireTokenSilent method will fail. Reasons for failure might be that the user has either signed out or changed their password on another device. When MSAL detects that the issue can be resolved by requiring an interactive action, it fires an MsalUiRequiredException exception. Your application can handle this exception in two ways:

  • It can make a call against AcquireTokenInteractive immediately. This call results in prompting the user to sign in. This pattern is usually used in online applications where there is no available offline content for the user. The sample generated by this guided setup follows this pattern, which you can see in action the first time you execute the sample.

  • Because no user has used the application, PublicClientApp.Users.FirstOrDefault() contains a null value, and an MsalUiRequiredException exception is thrown.

  • The code in the sample then handles the exception by calling AcquireTokenInteractive, which results in prompting the user to sign in.

  • It can instead present a visual indication to users that an interactive sign-in is required, so that they can select the right time to sign in. Or the application can retry AcquireTokenSilent later. This pattern is frequently used when users can use other application functionality without disruption--for example, when offline content is available in the application. In this case, users can decide when they want to sign in to either access the protected resource or refresh the outdated information. Alternatively, the application can decide to retry AcquireTokenSilent when the network is restored after having been temporarily unavailable.

Call the Microsoft Graph API by using the token you just obtained

Add the following new method to your MainWindow.xaml.cs. The method is used to make a GET request against Graph API by using an Authorize header:

/// <summary>
/// Perform an HTTP GET request to a URL using an HTTP Authorization header
/// </summary>
/// <param name="url">The URL</param>
/// <param name="token">The token</param>
/// <returns>String containing the results of the GET operation</returns>
public async Task<string> GetHttpContentWithToken(string url, string token)
{
    var httpClient = new System.Net.Http.HttpClient();
    System.Net.Http.HttpResponseMessage response;
    try
    {
        var request = new System.Net.Http.HttpRequestMessage(System.Net.Http.HttpMethod.Get, url);
        //Add the token in Authorization header
        request.Headers.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
        response = await httpClient.SendAsync(request);
        var content = await response.Content.ReadAsStringAsync();
        return content;
    }
    catch (Exception ex)
    {
        return ex.ToString();
    }
}

More information about making a REST call against a protected API

In this sample application, you use the GetHttpContentWithToken method to make an HTTP GET request against a protected resource that requires a token and then return the content to the caller. This method adds the acquired token in the HTTP Authorization header. For this sample, the resource is the Microsoft Graph API me endpoint, which displays the user's profile information.

Add a method to sign out a user

To sign out a user, add the following method to your MainWindow.xaml.cs file:

/// <summary>
/// Sign out the current user
/// </summary>
private async void SignOutButton_Click(object sender, RoutedEventArgs e)
{
    var accounts = await App.PublicClientApp.GetAccountsAsync(); 

    if (accounts.Any())
    {
        try
        {
            await App.PublicClientApp.RemoveAsync(accounts.FirstOrDefault());
            this.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}";
        }
    }
}

More information about user sign-out

The SignOutButton_Click method removes users from the MSAL user cache, which effectively tells MSAL to forget the current user so that a future request to acquire a token will succeed only if it is made to be interactive.

Although the application in this sample supports single users, MSAL supports scenarios where multiple accounts can be signed in at the same time. An example is an email application where a user has multiple accounts.

Display basic token information

To display basic information about the token, add the following method to your MainWindow.xaml.cs file:

/// <summary>
/// Display basic information contained in the token
/// </summary>
private void DisplayBasicTokenInfo(AuthenticationResult authResult)
{
    TokenInfoText.Text = "";
    if (authResult != null)
    {
        TokenInfoText.Text += $"Username: {authResult.Account.Username}" + Environment.NewLine;
        TokenInfoText.Text += $"Token Expires: {authResult.ExpiresOn.ToLocalTime()}" + Environment.NewLine;
    }
}

More information

In addition to the access token that's used to call the Microsoft Graph API, after the user signs in, MSAL also obtains an ID token. This token contain a small subset of information that's pertinent to users. The DisplayBasicTokenInfo method displays the basic information that's contained in the token. For example, it displays the user's display name and ID, as well as the token expiration date and the string representing the access token itself. You can select the Call Microsoft Graph API button multiple times and see that the same token was reused for subsequent requests. You can also see the expiration date being extended when MSAL decides it is time to renew the token.

Register your application

You can register your application in either of two ways.

Option 1: Express mode

You can quickly register your application by doing the following:

  1. Go to the Azure portal - Application Registration.
  2. Enter a name for your application and select Register.
  3. Follow the instructions to download and automatically configure your new application with just one click.

Option 2: Advanced mode

To register your application and add your application registration information to your solution, do the following:

  1. Sign in to the Azure portal using either a work or school account or a personal Microsoft account.

  2. If your account gives you access to more than one tenant, select your account in the top right corner, and set your portal session to the desired Azure AD tenant.

  3. Navigate to the Microsoft identity platform for developers App registrations page.

  4. Select New registration.

    • In the Name section, enter a meaningful application name that will be displayed to users of the app, for example Win-App-calling-MsGraph.
    • In the Supported account types section, select Accounts in any organizational directory and personal Microsoft accounts (for example, Skype, Xbox, Outlook.com).
    • Select Register to create the application.
  5. In the list of pages for the app, select Authentication.

    1. In the Redirect URIs section, in the Redirect URIs list:
    2. In the TYPE column select Public client (mobile & desktop).
    3. Enter urn:ietf:wg:oauth:2.0:oob in the REDIRECT URI column.
  6. Select Save.

  7. Go to Visual Studio, open the App.xaml.cs file, and then replace Enter_the_Application_Id_here with the application ID that you just registered and copied.

    private static string ClientId = "Enter_the_Application_Id_here";
    

Test your code

To run your project, in Visual Studio, select F5. Your application MainWindow is displayed, as shown here:

Test your application

The first time that you run the application and select the Call Microsoft Graph API button, you're prompted to sign in. Use an Azure Active Directory account (work or school account) or a Microsoft account (live.com, outlook.com) to test it.

Sign in to the application

The first time that you sign in to your application, you're also prompted to provide consent to allow the application to access your profile and sign you in, as shown here:

Provide your consent for application access

View application results

After you sign in, you should see the user profile information that's returned by the call to the Microsoft Graph API. The results are displayed in the API Call Results box. Basic information about the token that was acquired via the call to AcquireTokenInteractive or AcquireTokenSilent should be visible in the Token Info box. The results contain the following properties:

Property Format Description

|Username |user@domain.com |The username that is used to identify the user.| |Token Expires |DateTime |The time at which the token expires. MSAL extends the expiration date by renewing the token as necessary.|

More information about scopes and delegated permissions

The Microsoft Graph API requires the user.read scope to read a user's profile. This scope is automatically added by default in every application that's registered in the Application Registration Portal. Other APIs for Microsoft Graph, as well as custom APIs for your back-end server, might require additional scopes. The Microsoft Graph API requires the Calendars.Read scope to list the user’s calendars.

To access the user’s calendars in the context of an application, add the Calendars.Read delegated permission to the application registration information. Then, add the Calendars.Read scope to the acquireTokenSilent call.

Note

The user might be prompted for additional consents as you increase the number of scopes.

Help and support

If you need help, want to report an issue, or want to learn more about your support options, see the following article:

Help us improve the Microsoft identity platform. Tell us what you think by completing a short two-question survey.