Garethp / php-ews

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

Oauth is not working with Exchange 2013 #250

Open Matt504 opened 1 year ago

Matt504 commented 1 year ago

Hi @Garethp, first of all thank you for making this SOAP API to communicate with EWS, it does me a great service in making my web application which my manager would use to view employee appointments based on availability. The problem that I currently have is that when I tried to switch from API::withUsernameAndPassword to API::withCallbackToken, I get this error : Fatal error: Uncaught garethp\ews\API\Exception\UnauthorizedException in C:\xampp\htdocs\php-ews-fork\src\API\ExchangeWebServices.php:454.

What I did

I tried using your code in examples/basic/authentificatingWithOauth.php and did a few tweaks :

<?php
session_start();

require_once "../../vendor/autoload.php";

use garethp\ews\API;
use garethp\ews\API\ExchangeWebServicesAuth;
use garethp\ews\API\ExchangeWebServices;

$tokenEndpoint = 'https://login.microsoftonline.com/tenant-id/oauth2/v2.0/token';
$authorizationEndpoint = 'https://login.microsoftonline.com/tenant-id/oauth2/v2.0/authorize';
$clientId = '...';
$clientSecret = '...';
$redirectUri = 'http://localhost/php-ews-fork/examples/basic/authenticatingWithOAuth.php';
$resource = 'https://mail.company.com';

//The first step is to get your authorization code. It's a one time use code that needs to be granted by the user. You
//should have your own way to get it, but just for the sake of example I'm going to show you a way to do that

if (!isset($_SESSION['token']) && !isset($_GET['code'])) {
    $redirect = $authorizationEndpoint .
        '?response_type=code' .
        '&client_id=' . urlencode($clientId) .
        '&redirect_uri=' . urlencode($redirectUri) .
        '&scope=' . urlencode('EWS.AccessAsUser.All');
    header("Location: {$redirect}");
    exit();
}
elseif (isset($_GET['code'])) {
    //Once you have your code, you can exchange it for a token. The code can only be used once, so you don't store the code.
    //The token is what we'll be using for the duration of the session, so you should store between pages.

    $code = $_GET['code'];

    $token = ExchangeWebServicesAuth::getTokenFromAuthorizationCode(
        $clientId,
        $clientSecret,
        $code,
        $redirectUri,
        $tokenEndpoint
    );

    $_SESSION['token'] = $token;
}

//Once you have your token you can just create your API as easily as before, but with the token instead of with a
//username and a password

$token = $_SESSION['token'];

echo $token;

$api = API::withCallbackToken('mail.company.com', $token);

$calendar = $api->getCalendar();
...

The token here is displayed correctly, however, when I call getCalendar(), I get the error.

I also, change a few things in the ExchangeWebServicesAuth.php file :

public static function getTokenFromAuthorizationCode(
        $clientId,
        $clientSecret,
        $authorizationCode,
        $redirectUri,
        $tokenEndPoint = 'https://login.microsoftonline.com/common/oauth2/v2.0/token'
    ) {
        $postOptions = array(
            'http_errors' => false,
            'form_params' => array(
                'client_id' => $clientId, //Don't need resource nor client_secret because Client is public nor resource
                'code' => $authorizationCode,
                'redirect_uri' => $redirectUri,
                'grant_type' => 'authorization_code'
            )
        );

        $client = new Client();
        $response = $client->request('POST', $tokenEndPoint, $postOptions);
        $response = $response->getBody()->__toString();

        $response = json_decode($response);

        return $response->access_token;
    }

Note

I did find two quick fixes for this issue :

I did a lot of research but find nothing relevant to my problem so, if you or anyone had any clues as to what to do, anything at all, that would be a great help to me.