Description
Prerequisites
- I have searched for duplicate or closed issues
- I can recreate the issue with all plugins disabled
Describe the issue
I may be doing something wrong here, but my attempts to get IMAP XOAUTH2 authentication working for a tenant in Microsoft 365 have failed on a new install. I'll provide a sample of my configuration below.
<?php
// From html/config/config.inc.php
$config['default_host'] = 'ssl://outlook.office365.com';
$config['smtp_server'] = 'ssl://smtp.office365.com';
$config['oauth_provider'] = 'outlook';
$config['oauth_provider_name'] = 'Outlook.com';
$config['oauth_client_id'] = "-- snip --";
$config['oauth_client_secret'] = "-- snip --";
$config['oauth_auth_uri'] = "https://login.microsoftonline.com/common/oauth2/v2.0/authorize";
$config['oauth_token_uri'] = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
$config['oauth_identity_uri'] = "https://graph.microsoft.com/v1.0/me";
$config['oauth_identity_fields'] = ['email', 'userPrincipalName'];
$config['oauth_scope'] = "https://outlook.office365.com/IMAP.AccessAsUser.All https://outlook.office365.com/SMTP.Send User.Read offline_access";
$config['oauth_auth_parameters'] = ['nonce' => mt_rand()];
I can confirm that I have configured my application in Entra to include the requisite Graph API delegated permissions. I've also configured my scope for Multitenant without personal accounts ie. the Manifest for my application in Entra admin center shows "signInAudience": "AzureADMultipleOrgs". I've seen some other forums mention that this is required and it won't work with other SignInAudience values? Is this true, and if so, should it be added to the example configuration in defaults.inc.php?
When I connect with the above configuration, I get an incorrect audience error when attempting to fetch user details from the identity uri (graph.microsoft.com). When I use the graph namespace instead, I get "NO AUTHENTICATION failed." during IMAP login.
I created my own minimal oauth 365 proof of concept to see if I could rule out roundcube as the problem. Based on my findings, and skipping the identity uri call using the same scope as above, I was able to get imap auth working.
I think the problem may be that you cannot (can no longer? maybe this restriction was added recently?) use the same token on two different 365 resources. If you fetch a token that has scopes which are allowed to call the graph endpoint (prefixed with https://graph.microsoft.com), then the token fails for IMAP/SMTP. If you fetch a token which is allowed to authenticate for IMAP/SMTP (prefixed with https://outlook.office365.com), then the token fails for graph calls.
See this article:
https://stackoverflow.com/questions/48579143/one-or-more-scopes-are-not-compatible-with-each-other-error-when-retrieving-ac/48584417#48584417
The above url sounds like a similar issue, but with OneDrive and the 365 API instead of Graph and 365? It appears that you could make a call to the graph endpoint using graph scopes, then refresh the token with 365 scopes and use it for subsequent imap/smtp authentication. You would need to be able to define in config optional separate scopes for the identity fetch step, and then implement support for switching scopes after identity fetch is completed.
Can someone verify that this is a problem and I haven't missed something fundamental? If so, I think I can roll a pull-request that would fix by making updates to defaults.inc.php, rcube_imap_generic.php and rcmail_oauth.php.
What browser(s) are you seeing the problem on?
Chrome
What version of PHP are you using?
v8.0
What version of Roundcube are you using?
v1.5.8
JavaScript errors
No response
PHP errors
When Graph works:
20-Aug-2024 18:52:28 +0100]: IMAP Error: Login failed for --SNIP-- against outlook.office365.com from --SNIP--. AUTHENTICATE XOAUTH2: A0001 NO AUTHENTICATE failed. in /var/www/program/lib/Roundcube/rcube_imap.php on line 211 (GET /index.php/login/oauth?code=...
When Graph fails:
[20-Aug-2024 22:09:03 +0100]: PHP Error: OAuth token request failed: Client error: GET https://graph.microsoft.com/v1.0/me
resulted in a 401 Unauthorized
response:
{"error":{"code":"InvalidAuthenticationToken","message":"Access token validation failure. Invalid audience.","innerError (truncated...)
; eb9d0294d4de GuzzleHttp/6.5.5 curl/7.68.0 PHP/8.0.30 - [20/Aug/2024:22:09:03 +0100] "GET /v1.0/me HTTP/1.1" 401 in /var/www/html/program/include/rcmail_oauth.php on line 317 ...