Access with PHP to Exchange/Office 365

Long announced - now reality : Microsoft has switched off authentication by password for certain protocols in Exchange Online from September 2022 in favor of oAuth2. The GitHub issues of many libraries and backup scripts make it clear that the changeover caught many administrators by surprise. Below we show a way how you can continue to access the contents of your Exchange mailbox with the help of oAuth2 via PHP via IMAP.


From a security point of view, Microsoft's move is very correct, but the complexity of programmatic access to its e-mails has increased quite a bit. For example, if you use the widely used barbushin/php-imap library , access used to be as follows:

734a82898010e2fcb02c72c3cd9702c2

It just doesn't work anymore. In order to establish a connection via oAuth2, the first difficulty is to get the access token. And for this you have to take on two hurdles.

Azure Active Directory

The following steps register a new app in Azure Active Directory:

Login to https://portal.azure.com
Open the "Azure Active Directory"
Select "App registrations" & "New registration".
Copy "Application ID (Client)" (=Client ID) & "Directory ID (Tenant)" (=Tenant ID).
"API Permissions" & "Add Permission"
"APIs used by my organization" & "Office 365 Exchange Online"
"Application Permissions" & "IMAP.AccessAsApp"
Grant admin consent
"Certificates & Secrets" & "Client Secrets" & "New Client Secret"
Choose description and set validity
Copy "Secret ID" (Client Secret) to the clipboard
Open enterprise applications
Copy "Object ID".

PowerShell

Now we turn the app in the Microsoft PowerShell (Administrator mode) and assign permissions to the individual mailboxes (<TENANTID>, <CLIENTID>, <OBJECTID>, <EMAIL> must be replaced in each case):

Install-Module -Name ExchangeOnlineManagement
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -Organization <TENANTID>

New-ServicePrincipal -AppId <CLIENTID> -ServiceId <OBJECTID>
Add-MailboxPermission -Identity "<EMAIL>" -User <OBJECTID> -AccessRights FullAccess
...

Once you've done that, the rest isn't rocket science. Since barbushin/php-imap does not support oAuth2, you can connect with the alternative library Webklex/php-imap (which also has the advantage of not requiring the PHP IMAP module ).:

734a82898010e2fcb02c72c3cd9702c2

However, libraries that do not officially support oAuth2 can also be used with a proxy such as simonrob/email-oauth2-proxy make it workable. After this Download and the installation via python -m pip install -r requirements-no-gui.txt (Python ≥3.6 required) you edit the file emailproxy.config e.g. as follows (replacing this time <TENANTID>, <CLIENTID>, <CLIENTSECRET> and <EMAIL>):

[Server setup]

[IMAP-1993]
local_address = localhost
server_address = outlook.office365.com
server_port = 993

[Account setup]

[<EMAIL>]
token_url = https://login.microsoftonline.com/<TENANTID>/oauth2/v2.0/token
oauth2_scope = https://outlook.office365.com/.default
redirect_uri = http://localhost:8080
client_id = <CLIENTID>
client_secret = <CLIENTSECRET>

Then you start the proxy with python emailproxy.py --no-gui and can now go to the IP unencrypted localhost on port 1993 connect via regular Basic Auth (and any password set). If you want to start the proxy as a service in the background when you start the system, you can use, for example systemd:

sudo systemctl edit --force --full emailproxy.service

[Unit]
Description=Email OAuth 2.0 Proxy
[Service]
ExecStart=/usr/bin/python /path/to/emailproxy.py --no-gui
Restart=always
[Install]
WantedBy=multi-user.target

sudo systemctl enable emailproxy.service --now
sudo systemctl status emailproxy.service
sudo systemctl start emailproxy.service

If an encrypted connection is required, this is also possible - for this you first create a private key and a self-signed certificate:

openssl genrsa -out key.pem 3072
openssl req -new -x509 -key key.pem -out cert.pem -days 360

Then reference is made in the emailproxy.config these two files:

local_key_path = /path/to/key.pem
local_certificate_path = /path/to/cert.pem
Back