I'm currently using Delegated Auth to get user photo as below:
var pcaOptions = new PublicClientApplicationOptions
{
ClientId = "ClientID",
TenantId = "TenantId"
};
var pca = PublicClientApplicationBuilder.CreateWithApplicationOptions(pcaOptions).Build();
var ewsScopes = new string[] { "https://outlook.office365.com/EWS.AccessAsUser.All" };
var authResult = await pca.AcquireTokenInteractive(ewsScopes).ExecuteAsync();
string email = "SomeEmail@email.com";
HttpWebRequest request = WebRequest.Create(string.Format("https://outlook.office365.com/EWS/Exchange.asmx/s/GetUserPhoto?email={0}&size=HR648x648", email)) as HttpWebRequest;
request.Headers.Add("Authorization", "Bearer " + authResult.AccessToken);
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse){
Stream stream = response.GetResponseStream();
using (MemoryStream ms = new MemoryStream())
{
string encodedPhoto = Convert.ToBase64String((ms.ToArray()));
}
}
I'm trying to change to use App-Only Authentication. I managed to get the access token, but seems like it can't be done the same way as Delegated Auth.
Below is what I did to switch to use App-Only Authentication.
var cca = ConfidentialClientApplicationBuilder
.Create("ClientID")
.WithClientSecret("ClientSecret")
.WithTenantId("TenantID")
.Build();
var ewsScopes = new string[] { "https://outlook.office365.com/.default" };
var authResult = await cca.AcquireTokenForClient(ewsScopes).ExecuteAsync();
string email = "SomeEmail@email.com";
HttpWebRequest request = WebRequest.Create(string.Format("https://outlook.office365.com/EWS/Exchange.asmx/s/GetUserPhoto?email={0}&size=HR648x648", email)) as HttpWebRequest;
request.Headers.Add("Authorization", "Bearer " + authResult.AccessToken);
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse){
//Error: The remote server returned an error: (400) Bad Request.
Stream stream = response.GetResponseStream();
using (MemoryStream ms = new MemoryStream())
{
string encodedPhoto = Convert.ToBase64String((ms.ToArray()));
}
}
Error: The remote server returned an error: (400) Bad Request.
Edit: Updated to use SOAP operation as below, but I got this error: "The remote server returned an error: (500) Internal Server Error."
Anything I might have missed?
var cca = ConfidentialClientApplicationBuilder
.Create("ClientID")
.WithClientSecret("ClientSecret")
.WithTenantId("TenantID")
.Build();
var ewsScopes = new string[] { "https://outlook.office365.com/.default" };
var authResult = await cca.AcquireTokenForClient(ewsScopes).ExecuteAsync();
HttpWebRequest request = WebRequest.Create("https://outlook.office365.com/EWS/Exchange.asmx") as HttpWebRequest;
request.Headers.Add("Authorization", "Bearer " + authResult.AccessToken);
request.Method = "POST";
XmlDocument SOAPReqBody = new XmlDocument();
SOAPReqBody.LoadXml(@"<?xml version=""1.0"" encoding=""utf-8"" ?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:t=""https://schemas.microsoft.com/exchange/services/2006/types"" xmlns:m=""https://schemas.microsoft.com/exchange/services/2006/messages"">
<soap:Header>
<t:RequestServerVersion Version=""Exchange2013""/>
<t:ExchangeImpersonation>
<t:ConnectingSID>
<t:PrimarySmtpAddress>impersonatedUser@mail.com</t:PrimarySmtpAddress>
</t:ConnectingSID>
</t:ExchangeImpersonation>
</soap:Header>
<soap:Body>
<m:GetUserPhoto>
<m:Email>UserEmail@mail.com</m:Email>
<m:SizeRequested>HR648x648</m:SizeRequested>
</m:GetUserPhoto>
</soap:Body>
</soap:Envelope>");
using (Stream stream = request.GetRequestStream())
{
SOAPReqBody.Save(stream);
}
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse){
//The remote server returned an error: (500) Internal Server Error.
Stream stream = response.GetResponseStream();
using (MemoryStream ms = new MemoryStream())
{
string encodedPhoto = Convert.ToBase64String((ms.ToArray()));
}
}
The app token in EWS requires that you impersonate a known user (as you requests then take on that identity) so you would need to use the SOAP operation https://learn.microsoft.com/en-us/exchange/client-developer/web-service-reference/getuserphoto-operation and then impersonate a real-user (if you having Application policies you would need to be careful which one otherwise any user in the tenant should work) eg
var cca = ConfidentialClientApplicationBuilder
.Create("d4")
.WithClientSecret("s")
.WithTenantId("x")
.Build();
var ewsScopes = new string[] { "https://outlook.office365.com/.default" };
var authResult = cca.AcquireTokenForClient(ewsScopes).ExecuteAsync().Result;
HttpWebRequest request = WebRequest.Create("https://outlook.office365.com/EWS/Exchange.asmx") as HttpWebRequest;
request.Headers.Add("Authorization", "Bearer " + authResult.AccessToken);
request.Method = "POST";
XmlDocument SOAPReqBody = new XmlDocument();
SOAPReqBody.LoadXml(@"<?xml version=""1.0"" encoding=""utf-8""?>
<soap:Envelope xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:m=""http://schemas.microsoft.com/exchange/services/2006/messages"" xmlns:t=""http://schemas.microsoft.com/exchange/services/2006/types"" xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"">
<soap:Header>
<t:RequestServerVersion Version=""Exchange2016"" />
<t:ExchangeImpersonation>
<t:ConnectingSID>
<t:SmtpAddress>user@domain.com</t:SmtpAddress>
</t:ConnectingSID>
</t:ExchangeImpersonation>
</soap:Header>
<soap:Body>
<m:GetUserPhoto>
<m:Email>user@domain.com</m:Email>
<m:SizeRequested>HR48x48</m:SizeRequested>
</m:GetUserPhoto>
</soap:Body>
</soap:Envelope>");
using (Stream stream = request.GetRequestStream())
{
SOAPReqBody.Save(stream);
}
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
//The remote server returned an error: (500) Internal Server Error.
Stream stream = response.GetResponseStream();
XmlDocument Response = new XmlDocument();
Response.Load(stream);
var PictureDataNodes = Response.GetElementsByTagName("PictureData");
Byte[] PictureData = Convert.FromBase64String(PictureDataNodes[0].InnerText);
File.WriteAllBytes("c:\\temp\\pictest.jpg", PictureData);
}
}