Hello,
I would like to access an Office 365 mailbox using OAuth Application permissions.
If I’m not mistaken, the code sample in OAuth2 support for O365 uses OAuth Delegated permissions and not Application permissions.
When we use the following code to implement an ITokenProvider:
internal class AzureTokenProvider : ITokenProvider
{
private readonly string _tenantId;
private readonly string _clientId;
private readonly string _clientSecret;
private readonly string[] _scopes;
private readonly object _tokenSyncObj = new object();
private OAuthToken _token;
/// <summary>
/// Initializes a new instance of the <see cref="AzureTokenProvider"/> class
/// </summary>
public AzureTokenProvider(string tenant, string clientId, string clientSecret, string[] scopes)
{
_tenantId = tenant;
_clientId = clientId;
_clientSecret = clientSecret;
_scopes = scopes;
}
/// <summary>
/// Gets OAuth access token.
/// </summary>
/// <param name="ignoreExistingToken">
/// If ignoreExistingToken is true, requests new token from a server. Otherwise behaviour is depended on whether token exists or not.
/// If token exists and its expiration date is not expired returns current token, otherwise requests new token from a server.
/// </param>
/// <returns>Returns oAuth access token</returns>
public virtual OAuthToken GetAccessToken(bool ignoreExistingToken)
{
lock (_tokenSyncObj)
{
if (_token != null && !this._token.Expired && !ignoreExistingToken)
return _token;
_token = GetNewAccessToken();
return _token;
}
}
/// <summary>
/// Gets oAuth access token.
/// If token exists and its expiration date is not expired returns current token, otherwise requests new token from a server.
/// </summary>
/// <returns>Returns oAuth access token</returns>
public OAuthToken GetAccessToken()
{
return GetAccessToken(false);
}
private OAuthToken GetNewAccessToken()
{
// https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth
var app = ConfidentialClientApplicationBuilder
.Create(_clientId)
.WithAuthority(AzureCloudInstance.AzurePublic, _tenantId)
.WithClientSecret(_clientSecret)
.Build();
//Make the token request
var authResultTask = app.AcquireTokenForClient(_scopes).ExecuteAsync();
var authResult = authResultTask.Result;
return new OAuthToken(authResult.AccessToken, TokenType.AccessToken, authResult.ExpiresOn.LocalDateTime);
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public virtual void Dispose()
{
}
}
And use the following code to connect:
var ewsScopes = new string[] { "https://outlook.office.com/.default" };
var azureTokenProvider = new AzureTokenProvider(_mailboxSettings.AzureTenantId,
_mailboxSettings.AzureClientId,
_mailboxSettings.AzureClientSecret,
ewsScopes);
NetworkCredential credentials = new OAuthNetworkCredential(_mailboxSettings.Username, azureTokenProvider);
_ewsClient = EWSClient.GetEWSClient(_mailboxSettings.Host, credentials);
we always get the following exception:
System.Web.Services.Protocols.SoapException
HResult=0x80131501
Message=ExchangeImpersonation SOAP header must be present for this type of OAuth token.
Source=System.Web.Services
StackTrace:
at System.Web.Services.Protocols.SoapHttpClientProtocol.ReadResponse(SoapClientMessage message, WebResponse response, Stream responseStream, Boolean asyncCall)
at System.Web.Services.Protocols.SoapHttpClientProtocol.Invoke(String methodName, Object[] parameters)
at #=zXtdwOglEJf$aKzfPTIvDlrbACe_cFhBgycEaMNg8xwNKGTyUxA==.GetFolder(GetFolderType GetFolder1)
at Aspose.Email.Clients.Exchange.WebService.EWSClient.GetEWSClient(String mailboxUri, ICredentials credentials, WebProxy proxy)
at Aspose.Email.Clients.Exchange.WebService.EWSClient.GetEWSClient(String mailboxUri, ICredentials credentials)
at GenericDocumentImport.Modules.Email.ExchangeProtocolApi.CheckClient()
We are using Aspose.Email version 20.02