Search code examples
phplaravelimap

Webklex\PHPIMAP Modern Auth Not Working 365


As with most people, Microsoft are turning off basic authentication. This means we need to use Modern Auth to retrieve emails from a mailbox.

We've been able to implement retrieval of the access token, however, when we establish a connection to IMAP the connection fails with "NO LOGIN failed"

Here is the code we have for retrieving and connecting to IMAP.

/* Get the access Token */
$Secret = '**REMOVED**';
$AppID = '**REMOVED**';
$TenantID = '**REMOVED**';
$AccessToken = '';
try {
    $guzzle = new \GuzzleHttp\Client(['headers' => ['User-Agent' => 'App-Token-Request']]);
    $url = 'https://login.microsoftonline.com/'.$TenantID.'/oauth2/v2.0/token';
    $token = json_decode($guzzle->post($url, [
    'form_params' => [
        'grant_type'    => 'password', 
        'client_id'     => $AppID,
        'client_secret' => $Secret,
        'scope'         => 'https://graph.microsoft.com/.default', //'https://outlook.office365.com/IMAP.AccessAsUser.All',// 'https://graph.microsoft.com/.default',
        'username'      => '**REMOVED**',
        'password'      => '**REMOVED**',
    ], 
    ])->getBody()->getContents());
            
    $this->info(var_dump($token));
    $AccessToken = $token->access_token;

} catch (\League\OAuth2\Client\Provider\Exception\IdentityProviderException $e) {
    dd($e);
    return redirect('/')->with('error', 'Error requesting access token')->with('errorDetail', json_encode($e->getResponseBody()));
}

/* Connect to IMAP */
try {
    $cm = new \Webklex\PHPIMAP\ClientManager;
    $client = $cm->make([
        'host' => 'outlook.office365.com',
        'port' => 993,
        'encryption' => 'ssl',
        'validate_cert' => true,
        'username' => '**REMOVED**',
        'password' =>  $AccessToken,
        'protocol' => 'imap',
        'authentication' => "oath2"
    ]);

    $client->connect();
    $aFolder = $client->getFolder('FolderName');
    $aMessageOBJ = $aFolder->query()->all();
    $MessageCount = (clone $aMessageOBJ)->get()->count();
    $this->info("Found $MessageCount to process.");
    dd($client);
} catch (Exception $ex){
    dd($ex);
}

Getting the Auth token works, however connecting to IMAP fails. The output of the above code brings back the following:

class stdClass#1897 (5) {
  public $token_type =>
  string(6) "Bearer"
  public $scope =>
  string(183) "profile openid email https://graph.microsoft.com/IMAP.AccessAsUser.All https://graph.microsoft.com/SMTP.Send https://graph.microsoft.com/User.Read https://graph.microsoft.com/.default"
  public $expires_in =>
  int(4584)
  public $ext_expires_in =>
  int(4584)
  public $access_token =>
  string(2054) "**REMOVED**"...
}

>> TAG1 LOGIN "[email protected]" "**AUTHTOKEN**"
<< NO LOGIN failed.

>> TAG2 LOGOUT
<< BYE Microsoft Exchange Server IMAP4 server signing off.

<< OK LOGOUT completed.


In Client.php line 376:

  connection setup failed


In Client.php line 373:

  [Webklex\PHPIMAP\Exceptions\AuthFailedException]

Any suggestions on how to get the IMAP part working> I'm using "webklex/laravel-imap": "2.*",


Solution

  • Change the option 'authentication' => "oath2" to 'authentication' => "oath".

    This is because the Webklex\PHPIMAP\Client checks for the string 'oauth', not 'oauth2'. (Perhaps suggest this as an enhancement) to Webklex\PHPIMAP

    The response upon unsuccessful authentication should not be "NO LOGIN failed" it should be "NO AUTHENTICATION failed". That way you know it was requested as an XOAUTH2 request.