Garethp / php-ews

PHP Exchange Web Services
BSD 3-Clause "New" or "Revised" License
112 stars 45 forks source link

Cannot authorize with daemon app - The token contains not enough scope to make this call #222

Closed janh-kramer closed 3 years ago

janh-kramer commented 3 years ago

I try to connect to a on premise ews-Service as a daemon app to fetch calendar items from different users/ressources. The App is registered in Azure AD and got the the application permission "full_access_as_app" and "Calendars.ReadWrite.All" I am able retrieve a token from https://login.microsoftonline.com/TENANT-ID/oauth2/v2.0/token which includes the following details:

"aud": "https://mail.TENANT.URL",
...
"roles": [
    "full_access_as_app",
    "Calendars.ReadWrite.All"
  ],

With this token a make following call:

$options['version'] = ExchangeWebServices::VERSION_2013_SP1;

$options['trace'] = 1;
$options['exceptions'] = 0;
$options['impersonation'] = 'resource@tenant.url';

$api = API::withCallbackToken('mail.TENANT.URL', TOKEN, $options);
$calendar = $api->getCalendar();
$calendar->getCalendarItems('2021-05-01', '2021-12-31'));

But I get 403 response from the server, breakpoint in NTLMSoapClient.php (215), function __doRequest

$response = $this->httpClient->post($location, $postOptions);
dd($response);

gives me:

GuzzleHttp\Psr7\Response
  -reasonPhrase: "Forbidden"
  -statusCode: 403
  -headers: array:17 [
    "Date" => array:1 [
      0 => "Fri, 24 Sep 2021 07:51:14 GMT"
    ]
    "Server" => array:1 [
      0 => "Apache"
    ]
    "Cache-Control" => array:1 [
      0 => "private"
    ]
        ...
    "x-ms-diagnostics" => array:1 [
      0 => "2000008;reason="The token contains not enough scope to make this call.";error_category="invalid_grant""
    ]

I tried to hard code a X-AnchorMailbox header, as suggested here: https://docs.microsoft.com/en-us/archive/blogs/webdav_101/best-practices-ews-authentication-and-access-issues, Always set X-AnchorMailbox when using EWS Impersonation:

$postOptions = array(
            'body' => $request,
            'headers' => array(
                'Connection' => 'Keep-Alive',
                'User-Agent' => 'PHP-SOAP-CURL',
                'Content-Type' => 'text/xml; charset=utf-8',
                'SOAPAction' => $action,
                'X-AnchorMailbox' => 'resource@tenant.url'
            ),
            'verify' => $this->validate,
            'http_errors' => false
        );

But this changes nothing ..

What am I missing? With "full_access_as_app", and "Calendars.ReadWrite.All" a should have the permission to the calendar items. Thanks in advance for your help.

Garethp commented 3 years ago

Can you post the code that you're using to fetch the token? Authentication issues aren't something I can usually help you with, but I'd suggest trying to get the token using the oauth authentication example

janh-kramer commented 3 years ago

Thank you for your help. It was a configuration error on server side, now it is working!

paladini commented 2 years ago

@janh-kramer , can you tell how did you solved your problem? What's the problem on the server side?

janh-kramer commented 2 years ago

@paladini, sorry for the late reply. Actually I don’t know, because I have no access to server side, and did not solve this problem myself. Keep in mind that basic authentication is deprecated: https://learn.microsoft.com/en-us/exchange/clients-and-mobile-in-exchange-online/deprecation-of-basic-authentication-exchange-online

jbostoen commented 1 year ago

Hi @janh-kramer , would be great if you could perhaps share the API permissions for the application in the MS Azure - Applications configuration?

janh-kramer commented 1 year ago

The thing is, you don't actually need Azure permissions to access calendar items via ews. For me, setting up a service account with impersonation was enough. To access M365 via the Graph Api, you need Azure permissions.