0
votes

I was to trying to build an app that connect to EWS with OAuth and application persmissions using the following example code from Microsoft (https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth)

I registered my application in Azure AD, set the Application permissions to full_access_as_app and generated a client secret.

But always when i start the app i get a 401 error code (Error: Microsoft.Exchange.WebServices.Data.ServiceRequestException: The request failed.)

When i use the code for delegated permissions and entered my username and password it works, but i need the feature tu run my app in background with ImpersonatedUserId.

using System;
using System.Configuration;
using Microsoft.Exchange.WebServices.Data;
using Microsoft.Identity.Client;

namespace ews_oauth_samples
{
    class Program
    {
        static void Main(string[] args)
        {
            MainAsync(args).Wait();

            if (System.Diagnostics.Debugger.IsAttached)
            {
                Console.WriteLine("Hit any key to exit...");
                Console.ReadKey();
            }
        }
        
        static async System.Threading.Tasks.Task MainAsync(string[] args)
        {
            // Configure the MSAL client to get tokens
            var ewsScopes = new string[] { "https://outlook.office.com/.default" };

            var app = ConfidentialClientApplicationBuilder.Create(ConfigurationManager.AppSettings["appId"])
                .WithAuthority(AzureCloudInstance.AzurePublic, ConfigurationManager.AppSettings["tenantId"])
                .WithClientSecret(ConfigurationManager.AppSettings["clientSecret"])
                .Build();

            AuthenticationResult result = null;

            try
            {
                // Make the interactive token request
                result = await app.AcquireTokenForClient(ewsScopes)
                    .ExecuteAsync();

                // Configure the ExchangeService with the access token
                var ewsClient = new ExchangeService();
                ewsClient.Url = new Uri("https://outlook.office365.com/EWS/Exchange.asmx");
                ewsClient.Credentials = new OAuthCredentials(result.AccessToken);

                //Impersonate the mailbox you'd like to access.
                ewsClient.ImpersonatedUserId = new ImpersonatedUserId(ConnectingIdType.SmtpAddress, "[email protected]");

                // Make an EWS call
                var folders = ewsClient.FindFolders(WellKnownFolderName.MsgFolderRoot, new FolderView(10));
                foreach (var folder in folders)
                {
                    Console.WriteLine($"Folder: {folder.DisplayName}");
                }
            }
            catch (MsalException ex)
            {
                Console.WriteLine($"Error acquiring access token: {ex.ToString()}");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.ToString()}");
            }
        }
    }
}
1
Have you tried to check the token that is generated with jwt.org (eg check that the scopes are okay)Glen Scales

1 Answers

0
votes

It is easy to miss something when you register the application, so try a new application and make sure you follow the additional steps to use Application permissions.

If the app Id, tenant Id and client secret are all correct you should not get the 401 error if you use the access token within 1 hour.

The 401 error is "normal" after the access token has expired. Your application needs to call AcquireTokenForClient to get a fresh token at least once an hour.

Even when the token is still fresh, the FindItems will probably fail on user "[email protected]", with a different error: "The SMTP address has no mailbox associated with it".