Call the Microsoft Graph API from a Windows Desktop app

This guide demonstrates how a native Windows Desktop .NET (XAML) application can get an access token and call the Microsoft Graph API or other APIs that require access tokens from an Azure Active Directory v2 endpoint.

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 or Visual Studio 2017. Don’t have either of these versions? Download Visual Studio 2017 for free.

How this guide works

How this guide 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 an Azure Active Directory v2 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 that can be used to query Microsoft Graph API or a Web API that's secured by Azure Active Directory v2.

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)

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 or WPF Application, 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.

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
    {
        //Below is the clientId of your app registration. 
        //You have to replace the below with the Application Id for your app registration
        private static string ClientId = "your_client_id_here";
    
        public static PublicClientApplication PublicClientApp = new PublicClientApplication(ClientId);
    
    }
    

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 AcquireTokenAsync - to acquire a token requiring user to sign-in
        /// </summary>
        private async void CallGraphButton_Click(object sender, RoutedEventArgs e)
        {
            AuthenticationResult authResult = null;
    
            try
            {
                authResult = await App.PublicClientApp.AcquireTokenSilentAsync(_scopes, App.PublicClientApp.Users.FirstOrDefault());
            }
            catch (MsalUiRequiredException ex)
            {
                // A MsalUiRequiredException happened on AcquireTokenSilentAsync. This indicates you need to call AcquireTokenAsync to acquire a token
                System.Diagnostics.Debug.WriteLine($"MsalUiRequiredException: {ex.Message}");
    
                try
                {
                    authResult = await App.PublicClientApp.AcquireTokenAsync(_scopes);
                }
                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 AcquireTokenAsync 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 AcquireTokenSilentAsync method handles token acquisitions and renewals without any user interaction. After AcquireTokenAsync is executed for the first time, AcquireTokenSilentAsync 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 AcquireTokenSilentAsync 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 AcquireTokenAsync 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 AcquireTokenAsync, 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 AcquireTokenSilentAsync 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 AcquireTokenSilentAsync 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 void SignOutButton_Click(object sender, RoutedEventArgs e)
{
    if (App.PublicClientApp.Users.Any())
    {
        try
        {
            App.PublicClientApp.Remove(App.PublicClientApp.Users.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 += $"Name: {authResult.User.Name}" + Environment.NewLine;
        TokenInfoText.Text += $"Username: {authResult.User.DisplayableId}" + Environment.NewLine;
        TokenInfoText.Text += $"Token Expires: {authResult.ExpiresOn.ToLocalTime()}" + Environment.NewLine;
        TokenInfoText.Text += $"Access Token: {authResult.AccessToken}" + 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 Microsoft Application Registration Portal.

  2. Select Add an app.

  3. In the Application Name box, enter a name for your application.

  4. Ensure that the Guided Setup check box is selected, and then select Create.

  5. Follow the instructions for obtaining the application ID, and paste it into your code.

Option 2: Advanced mode

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

  1. If you haven't already registered your application, go to the Microsoft Application Registration Portal.

  2. Select Add an app.

  3. In the Application Name box, enter a name for your application.

  4. Ensure that the Guided Setup check box is cleared, and then select Create.

  5. Select Add Platform, select Native Application, and then select Save.

  6. In the Application ID box, copy the GUID.

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

    private static string ClientId = "your_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 AcquireTokenAsync or AcquireTokenSilentAsync should be visible in the Token Info box. The results contain the following properties:

Property Format Description
Name User's full name The user’s first and last name.
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.
Access Token String The token string that is sent to HTTP requests that require an Authorization header.

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: