WPF App and Web API using Azure AD and MSAL

WPF App and Web API using Azure AD and MSAL

Let’s consider a scenario where a public client application needs to call a web API. Both of the applications are owned by you. And suppose, we want both of them to be secured using Azure AD and MSAL.

Let’s see how to get this setup working.

Securing Web API

We will have to register the API application in Azure AD. Then we will have to configure our web API application to use appropriate Client ID and Tenant ID. Also, we will have to configure middleware to allow only authenticated / authorized users to call the APIs.

Refer my previous blog article about securing web APIs for detailed steps.

Secure Web API using Azure AD
Secure Web API using Azure AD

Securing WPF Application

Create a .NET Core WPF application. Add reference to Microsoft.Identity.Client NuGet package and register the application in same Azure AD instance.

Refer my blog post for detailed steps on how to setup authentication in WPF app.

Authentication in WPF App using Azure AD

So, now we have a Web API secured using Azure AD and a WPF app secured using Azure AD. WPF app is not setup yet to call the Web API.

Let’s have a look at next steps.

Azure AD Permissions

Login to Azure Portal and go to Azure Active Directory tenant where both API and WPF application are registered.

Open the app registration which was created for WPF application.

Then select API permissions from the left navigation and click on Add a permission button. It will open a panel where you can select APIs.

Select My APIs tab and then select the web API which is registered few min back. In this case, I will select SampleWebApi from the list.

Azure AD - Request API Permission for WPF App
Azure AD – Request API Permission for WPF App

On next screen, options will be shown to select the type of permissions required for WPF application – either Delegated Permissions or Application Permissions.

As users will be logging in to WPF application, we would want the API calls to run under the privileges of the logged in users. So, let’s select Delegated Permissions. Next, select the scope access_as_user and then click on Add permissions button.

Azure AD - Request API Permission for WPF App 2
Azure AD – Request API Permission for WPF App 2

WPF App Scopes

Now, we already have a WPF application where user can login. If you have followed this blog post, you might already be aware that only one scope was used for setting up login and it was User.Read.

The AuthenticationResult object which was returned after AcquireTokenInteractive method, has below important information:

  • id token, for identifying authenticated user
  • access token, for accessing the protected resources
  • scopes, the scopes for which token was granted
  • expiry, time at which the token would be expired

Now, let’s add the scope for the API that WPF app should call. This should be added to Scopes collection which is in the SignIn method. Because of this, the tokens received from Azure AD will have permission to call the Web API.

Below snippet shows the Sign In method.

private async void SignInButton_Click(object sender, RoutedEventArgs e)
{
string[] scopes = new string[] { "user.read", "api://5e999e55-a661-4982-b897-965480492129/access_as_user" };
AuthenticationResult authResult = null;
var app = App.PublicClientApp;
try
{
ResultText.Text = "";
authResult = await (app as PublicClientApplication).AcquireTokenInteractive(scopes)
.ExecuteAsync();
DisplayBasicTokenInfo(authResult);
UpdateSignInState(true);
}
catch (Exception ex)
{
ResultText.Text = $"Error Acquiring Token:{Environment.NewLine}{ex}";
}
}
view raw MainWindow.xaml.cs hosted with ❤ by GitHub

WPF App Call API

Now, lets see how to get the access token and then call the protected web API. The WPF app can get the token by calling AcquireTokenSilent().ExecuteAsync() call as shown in below snippet.

Then the AuthenticationResult returned by this call can be used to get the access token. This access token is then added in authorization header while calling API.

Below code does not show it, but if you get MsalUiRequiredException, then you should try calling AcquireTokenInteractive method to acquire token via interactive login.

private async void CallAPIButton_Click(object sender, RoutedEventArgs e)
{
string[] scopes = new string[] { "api://5e999e55-a661-4982-b897-965480492129/access_as_user" };
// This shows simplest version assuming there will not be errors
// while getting token silently. If there are, token should be acquired
// using interactive API
var accountList = await App.PublicClientApp.GetAccountsAsync();
var authResult = await App.PublicClientApp
.AcquireTokenSilent(scopes, accountList.FirstOrDefault())
.ExecuteAsync();
string accessToken = authResult.AccessToken;
string url = "https://localhost:44389/weatherforecast";
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
string json = await client.GetStringAsync(url);
ResultText.Text = json;
}
view raw MainWindow.xaml.cs hosted with ❤ by GitHub

There are various errors that may occur in this flow, but as this application is only for demo purpose, I have not listed them here. If you are curious to know, the errors can be found in sample documented at this page.

Run and Verify

If you try to run the application now, and try to hit Weather Forecast API button without signing in, then MsalUiRequiredException would be thrown. Ideally this exception should be handled and interactive sign in should be used to acquire the token.

MsalUiRequiredException thrown if user is not logged in
MsalUiRequiredException thrown if user is not logged in

Next after successful sign in, user clicks on Weather Forecast API button, the text box will show result from the API.

WPF App calling Web API, both protected using Azure AD
WPF App calling Web API, both protected using Azure AD

I hope you enjoyed this article. Let me know your thoughts.

Leave a Reply

This Post Has One Comment