I'm trying to convert some EWS scripts to use oauth. I've found that it works when the Azure registered app has been given application permission full_access_as_app, but not when its only set to delegated permissions EWS.AccessAsUser.All . It seems that if full_access_as_app is given then anyone with the appID and secret can access any mailbox. When EWS.AccessAsUser.All is given no one can access any mailbox. What I was hoping for is that the appID and secret were essentially keys to the gate, but then access to a mailbox would be based on if the particular user running the script, or the credentials passed with it (which I don't know how to do unless it's the logged on user), has permissions to the mailbox. So, essentially, you get in the gate, but then you use impersonation. It also doesn't seem that the app secret can be held in a secure hash file like credentials can, so the secret is exposed. Thank you for your help.
## Request an access token
# Define AppId, secret and scope, your tenant name and endpoint URL
$AppId = 'AppId'
$AppSecret = 'AppSecret'
$Scope = "https://outlook.office365.com/.default"
$TenantName = "domain.onmicrosoft.com"
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"
# Add System.Web for urlencode
Add-Type -AssemblyName System.Web
# Create body
$Body = @{
client_id = $AppId
client_secret = $AppSecret
scope = $Scope
grant_type = 'client_credentials'
}
# Splat the parameters for Invoke-Restmethod for cleaner code
$PostSplat = @{
ContentType = 'application/x-www-form-urlencoded'
Method = 'POST'
# Create string by joining bodylist with '&'
Body = $Body
Uri = $Url
}
# Request the token!
$Request = Invoke-RestMethod @PostSplat
#######################
$Email = "UserA@domain.com"
# Import "Microsoft Exchange Web Services Managed API 2.2"
Import-Module -Name "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll"
## Create the Exchange Service object with Oauth creds
$Service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService -ArgumentList Exchange2013_SP1
$service.Url= new-object Uri("https://outlook.office365.com/EWS/Exchange.asmx")
$Service.TraceEnabled = $true
$service.ImpersonatedUserId = new-object Microsoft.Exchange.WebServices.Data.ImpersonatedUserId([Microsoft.Exchange.WebServices.Data.ConnectingIdType]::SmtpAddress,$Email)
$service.HttpHeaders.Add("X-AnchorMailbox", $Email)
$Service.Credentials = New-Object Microsoft.Exchange.WebServices.Data.OAuthCredentials($Request.access_token)
$OAuthCredentials = New-Object Microsoft.Exchange.WebServices.Data.OAuthCredentials($Request.access_token)
$service.Credentials = $OAuthCredentials
#####################
# WellKnown folders to adjust
$folderNames = "Inbox"
Foreach($folderName in $folderNames)
{
# Set the WellKnownFolder
$FolderId = [Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::$folderName
# Bind to WellKnownFolder Notes
$folder = [Microsoft.Exchange.WebServices.Data.Folder]::Bind($Service, $folderId)
Write-Host "$($Email): $($folderName): " -NoNewline
$folder.archivetag.RetentionId.Guid
} # Foreach($folderName... END
######################
You should change to use delegated permission. With delegated permission, you will be able to access the API as a specific user.
So, you need to add EWS.AccessAsUser.All
permission, and get a token as following:
## Request an access token
# Define AppId, secret and scope, your tenant name and endpoint URL
$AppId = 'your app id'
$AppSecret = 'your app key'
$Scope = "https://outlook.office365.com/.default"
$TenantName = "{your_tenant}.onmicrosoft.com"
$Url = "https://login.microsoftonline.com/$TenantName/oauth2/v2.0/token"
# Add System.Web for urlencode
Add-Type -AssemblyName System.Web
# Create body
$Body = @{
client_id = $AppId
client_secret = $AppSecret
scope = $Scope
grant_type = 'password'
username = 'your user name here, e.g.,jack@hanxia.onmicrosoft.com'
password = 'your password here ******************'
}
# Splat the parameters for Invoke-Restmethod for cleaner code
$PostSplat = @{
ContentType = 'application/x-www-form-urlencoded'
Method = 'POST'
# Create string by joining bodylist with '&'
Body = $Body
Uri = $Url
}
# Request the token for user!
$Request = Invoke-RestMethod @PostSplat
$Request.access_token