javanile / php-imap2

PHP IMAP with OAUTH2
https://php-imap2.javanile.org/
GNU General Public License v3.0
54 stars 31 forks source link

MS Outlook connectivity #8

Closed cjwnz closed 2 years ago

cjwnz commented 2 years ago

Hi there

I'm having some issues connecting to Outlook. I can successfully obtain the Access Token using scope https://outlook.office.com/.default I'm then preparing the Access Token as follows:

base64_encode("user=".$username."\x01auth=Bearer $access_token\x01\x01");

But the call to imap2_open to {outlook.office365.com:993/imap/ssl}INBOX fails with:

Can not authenticate to IMAP server: A0001 NO AUTHENTICATE failed.

Anything obvious I'm doing wrong? Any examples connecting to Outlook 365 appreciated!

cjwnz commented 2 years ago

I have now resolved this issue. But I think if you want people to use this library you'd better start answering some of the issues ;-) Thanks.

rmaxe commented 2 years ago

Hi @cjwnz,

I've got the exact same issue, would you please share your solution? Thanks!

cjwnz commented 2 years ago

Hi rmaxe - make sure you follow closely all the instructions from Microsoft including the command-line powershell commands. It's not straight forward and we have prepared our own instructions/tips here:

http://wiki.canfigure.net/en/guides/exchange-oauth2

francescobianco commented 2 years ago

IMPORTANT!

You do not need encode the token on base64, this library already do it by itself

Avoid code like this (DO NOT DO THIS)

base64_encode("user=".$username."\x01auth=Bearer $access_token\x01\x01");

cc @cjwnz @rmaxe

francescobianco commented 2 years ago

TEST LIVE - Outlook

On this link you can test Microsoft Outlook connectivity https://php-imap-outlook.herokuapp.com/

darkworks commented 2 years ago

The annoying thing about outlook is that microsfot not offering any of their MSAL lib for php.

darkworks commented 2 years ago

Hi rmaxe - make sure you follow closely all the instructions from Microsoft including the command-line powershell commands. It's not straight forward and we have prepared our own instructions/tips here:

http://wiki.canfigure.net/en/guides/exchange-oauth2

thanks for the instructions . am getting access token however like my script when i trouble shoot with your powershell script i get same error ERROR during authentication A01 NO AUTHENTICATE failed.

am not able to follow this step image

i do not have office 365 online in the list as its due to because my email is xxxxxx@live.com ?? image

so far i have added these permissions

image

but unlike my script the power shell also return ERROR during authentication A01 NO AUTHENTICATE failed. image my php script can't connect: Can not authenticate to IMAP server: A0001 NO AUTHENTICATE failed.

also i do not have these settings Tools & Utils > System Settings in my Azure portal ? image here is screenshot of my Azure portal image

darkworks commented 2 years ago

[ 'applicationId' => '...', 'applicationSecret' => '...', 'scope' => [ 'wl.basic', 'wl.imap', 'wl.emails', 'wl.offline_access', 'https://outlook.office.com/IMAP.AccessAsUser.All', 'https://outlook.office.com/SMTP.Send', 'https://graph.microsoft.com/SMTP.Send', 'https://graph.microsoft.com/IMAP.AccessAsUser.All', ]

hmmmm can u tell how to pass these scopes to imap2_openfunction currently i have this

imap2_open($this->mail_server, $this->email_id, $this->access_token, OP_XOAUTH2 ) or die("can't connect: " . imap2_last_error());

thanks

darkworks commented 2 years ago

'wl.basic', 'wl.imap', 'wl.emails', 'wl.offline_access', 'https://outlook.office.com/IMAP.AccessAsUser.All', 'https://outlook.office.com/SMTP.Send', 'https://graph.microsoft.com/SMTP.Send', 'https://graph.microsoft.com/IMAP.AccessAsUser.All',

hmmm changed scopes however same issue. am using : https://github.com/TheNetworg/oauth2-azure

will change to Socialconnet to see if there is lib issue

darkworks commented 2 years ago

@Orgoth Ok so this is for log purpose if you keep getting error : ERROR during authentication A01 NO AUTHENTICATE failed.

adamhealthystuff commented 2 years ago

Social Connect This keeps redirecting me to a "We're unable to complete your request" page. The current social connect microsoft config seems to use the old microsoft apps which was deprecated in 2019?

How did you use Social Connect for azure? The azure-ad they added doesnt work either?

OAuth2-Azure ERROR during authentication A01 NO AUTHENTICATE failed.

Outlook Example Login ERROR during authentication A01 NO AUTHENTICATE failed.

darkworks commented 2 years ago

@Orgoth can you share you Outh issue maybe i can help you out. any error etc you getting.

darkworks commented 2 years ago

hmmm try with these scopes

    'scopes'    => [
        'offline_access',
        'https://outlook.office365.com/Mail.Read',
        'https://outlook.office365.com/profile',
        'https://outlook.office365.com/IMAP.AccessAsUser.All',
    ],

there is typo in Azur portal for business emails they show incorrect scopes like

https://graph.microsoft.com/offline_access,https://graph.microsoft.com/Mail.ReadWrite,https://graph.microsoft.com/Mail.Send,https://graph.microsoft.com

for business emails correct scopes are the one which i mentioned . the scopes which you are using currently will work only for non business emails mean free @live emails

darkworks commented 2 years ago

composer require thenetworg/oauth2-azure

then try something like this

require_once './vendor/autoload.php';

    // init outh client
    $microsoft_outh = new TheNetworg\OAuth2\Client\Provider\Azure([
    'clientId'          => 'your app client id',
    'clientSecret'      => 'app secret id',
    'redirectUri'       => 'redirect url must match with azure portal ',
    'approval_prompt' => 'auto',
    'scopes'    => [
        'offline_access',
        'https://outlook.office365.com/Mail.Read',
        'https://outlook.office365.com/profile',
        'https://outlook.office365.com/IMAP.AccessAsUser.All',
    ],
    'defaultEndPointVersion' => '2.0'
    ]);
darkworks commented 2 years ago

image

darkworks commented 2 years ago

hmmmm which outh lib you are using ? social connect or the one which i shared

darkworks commented 2 years ago

@Orgoth Ok so this is for log purpose if you keep getting error : ERROR during authentication A01 NO AUTHENTICATE failed. then make sure use SocialConnect : https://github.com/SocialConnect/auth avoid using this lib : oauth2-azure https://github.com/TheNetworg/oauth2-azure its buggy and you will get errors like ERROR during authentication A01 NO AUTHENTICATE failed.

You have stated, this lib is buggy, so I did not even consider it.

oh my apologies i have edit my comment . ya i had issues with that lib and then after trying about 4 outh libs i came to conclusion that this lib was OK : https://github.com/TheNetworg/oauth2-azure it was just that scopes were not correct due to typo in Azur portal. the social connect lib works ok with non-business emails it will not work with business emails. so install this lib ; https://github.com/TheNetworg/oauth2-azure

and then test. social connect i tested not work with business email however was ok with non business emails. and sorry for the trouble my comment had caused :(

darkworks commented 2 years ago

the social connect lib works ok with non-business emails it will not work with business emails. so install this lib ;

Yes, for business you need to create your own provider. The default provider by social connect can only call to https://login.live.com/oauth20_authorize.srf and https://login.live.com/oauth20_token.srf. For Business, you need to call https://login.microsoftonline.com/tenant/oauth2/v2.0/authorize and https://login.microsoftonline.com/common/v2.0/oauth2/token.

I have created my own provider by extending the existing and applying the new URLs. :)

I will try the lib by TheNetworg.

ya i had made changes too like that For Business, you need to call https://login.microsoftonline.com/tenant/oauth2/v2.0/authorize and https://login.microsoftonline.com/common/v2.0/oauth2/token.

but had no success with social connect

adamhealthystuff commented 2 years ago

@Orgoth

Could you share your azure auth script used for b2b?

I'm still getting the auth error using the above scopes with thenetworgs scripts.

darkworks commented 2 years ago

@adamhealthystuff you want to access business email or free user email ?

darkworks commented 2 years ago

@darkworks Thank you very much for the help. With the lib from TheNetworg it has indeed worked for B2B.

It would be really great if Microsoft would create a unified API here.

ya its very annoying they have different end points for business and non business emails . very annoying it should be one api for both

adamhealthystuff commented 2 years ago

@darkworks Business email, I'm currently trying to use thenetworgs script with the following.

$provider = new Azure([
        'clientId'          => $email_account->application_id,
        'clientSecret'      => $email_account->secret_value,
        'redirectUri'       => $email_account->redirect_uri,
        'tenant'            => $email_account->tenant_id,
        'approval_prompt' => 'auto',
        'scopes'    => [
            'offline_access',
            'https://outlook.office365.com/Mail.Read',
            'https://outlook.office365.com/profile',
            'https://outlook.office365.com/IMAP.AccessAsUser.All',
        ],
        'defaultEndPointVersion' => '2.0'
    ]);
darkworks commented 2 years ago

@adamhealthystuff so what error it give to you ?

also remove : 'tenant' => $email_account->tenant_id, no need of it

adamhealthystuff commented 2 years ago

@adamhealthystuff so what error it give to you ?

Can not authenticate to IMAP server: A0001 NO AUTHENTICATE failed.

$mailbox = imap2_open($server, $email_addr, $email_account->access_token, OP_XOAUTH2);

darkworks commented 2 years ago

so the app you have registered as account # 3 like this ?

image

adamhealthystuff commented 2 years ago

@darkworks

Thanks for your help btw yeah here are the permissions

image

Also

image
darkworks commented 2 years ago

Hmmmm focus on Microsfot graph API permission instead of office 365 exchange online.

you shared two screenshots and first screenshot have only 1 graph permission while 2nd have microsfot graph 4 permission . make sure you app have enough permission something like this

image

darkworks commented 2 years ago

there is one another confusion in Azur portal so make sure your secret key is correct

image the secret key is actually the Value not the Secret ID

adamhealthystuff commented 2 years ago

I've updated this and ensured I'm using the secret value but I'm still getting the auth issue above.

Do I need to extract the token from the JWT or simply pass the whole value returned from $access_token->getToken()

image
adamhealthystuff commented 2 years ago

@darkworks It finally works after adding more permissions to Graph API, thank you!

darkworks commented 2 years ago

@Orgoth hmmmm do you have access to your primary b2b email and can you login to : https://admin.microsoft.com/Adminportal/Home and send me screenshot so that i can guide you . you can hide users address in it. as it the moment i do not have access to admin account. from admin portal make sure the desire email is also authorized to use imap

darkworks commented 2 years ago

@darkworks Getting the token and refreshtoken works now with B2B. But I now get the same error :)

A0001 NO AUTHENTICATE failed.

I am using the recommended scopes:

   'offline_access',
   'https://outlook.office365.com/profile',
   'https://outlook.office365.com/Mail.ReadWrite',
   'https://outlook.office365.com/IMAP.AccessAsUser.All',
   'https://outlook.office365.com/SMTP.Send',

so you getting A0001 NO AUTHENTICATE failed. error with refresh token only or also newly assigned token too

darkworks commented 2 years ago

@Orgoth well access tokens are of two types one is fresh which you get by establishing fresh connection and another one is getting access token through refresh token. as when you get your first fresh token you will get refresh token with it. so u can save it to your session and then after hour when your access token expired then you can renew your access token through refresh token instead of requesting new fresh .

i refresh something like this, when their is about 5 min left in expire i renew it

            if (isset($token)) {

                $now = time() + 300;
                if ($_SESSION["token_expires"] <= $now) {
                try {

                    if (!is_null($_SESSION["refresh_token"])) {

                        $token = $this->microsoft_outh->getAccessToken('refresh_token', [
                        'scope' => $this->microsoft_outh->scope,
                        'refresh_token' => $_SESSION["refresh_token"]
                        ]);

                        $access_token = $this->update_token($token);
        public function update_token($token){
            $_SESSION['token_obj'] = $token;
            $_SESSION['access_token'] = $token->getToken();
            $_SESSION['refresh_token'] = $token->getRefreshToken();
            $_SESSION['token_expires'] = $token->getExpires();
            $this->access_token = $_SESSION['access_token'];
            return $_SESSION['access_token'];
        }