Has anyone found a working, explainable solution to this please??? 🙏

jerer

Maybe it’s too early and I’m not understanding you. The problem isn’t getting a graph token the problem is using the token to authenticate to IMAP/POP protocols (the only IMAP resource I know is outlook.office365.com:933 - don’t see a graph resource for this). When you authenticate using graph token it fails. Our code only supports fetching via IMAP/POP protocols we do not support fetching from retrieving mail via api calls. From all that I’ve read online graph tokens are solely used for graph api endpoints. Graph API endpoints require calling a API endpoint to retrieve mail; completely different than IMAP/POP protocols. IMAP is a protocol to fetch mail not an API endpoint. So my point is that the graph tokens are meant for graph api and graph api is only good for API calls and that essentially kills IMAP/POP which I doubt they are doing.

Cheers.

    jfields

    No, that is still explaining that you must switch to API calls to retrieve mail instead of using IMAP/POP3 protocols so that's not going to help here. Our software only supports IMAP/POP3 fetching or email piping or sending emails to our API (not us calling out to retrieve mail).

    Cheers.

    Also having the same issue. Our Token expired yesterday, and we are unable to refresh. Verified all the endpoints, secrets, etc. are correct.

    KevinTheJedi Any guidance or resources I can look into on how to do this? Referring to the instruction to get a graph token from graph and then use it for the imap endpoint.

      @jerer

      I really recommend you try this yourself. You can uncheck Strict Matching if it's not letting you get passed that part. But once you get a token with the user endpoint set to graph you can't authenticate to IMAP/POP3. If i'm missing something please let me know.

      Cheers.

      KevinTheJedi
      I understand that Outlook IMAP/SMTP/POP does not work if any Graph scopes are used. That's why you have been using the Outlook REST API.

      And now that the Outlook REST API has been deprecated (for many years) and decommissioning has begun, we can't use that anymore. The replacement for that is the Graph API, but I do understand we cannot use that either with the same access token we use Outlook IMAP/SMTP/POP.

      The only solution to this problem is to create 2 access tokens, one scoped for Graph and one scoped for Outlook IMAP/SMTP/POP. Or give us an option to skip that API call completely.

      That's what I have been trying to point out (since 2 years ago). I know dealing with these Microsoft things must be annoying, but it is what it is.

        jerer

        Why are two tokens needed...that definitely seems like an issue on their end that they need to address.

        The only reason the User Endpoint is used is to verify the email matches during token creation. Once the token is created it doesn't matter and it's not used; all outlook resources are used at that point. You can disable strict matching if it's giving you difficulties. But once you get a token you'll see authentication fails. The token is retrieved using the endpoints the app registration gives you.

        Cheers.

          Hola,
          OSticket ya no funciona mas con O365?

          jerer

          Just tried getting Graph token using graph scopes and endpoints and same issue. I was able to get a token successfully but can't auth to IMAP using Graph tokens... so definitely an issue on Microsoft side that they need to address.

          Cheers.

          jerer

          Confirmed that this works. Sucks to have to use a workaround, hopefully MS will fix something and it'll go back to working the right way at some point...

          Dav1d

          Yea but try to save the Remote Mailbox with IMAP configured and enabled and you'll see authentication fails.

          Cheers.

          @jerer

          I just did a test to remove the call to the user endpoint and it gets a token but still same authentication failed message when attempting to authenticate to IMAP and SMTP. So this definitely appears to be an issue on their end as I can't even auth using a token I'm given.

          Cheers.

            KevinTheJedi
            Yeah I can agree this is at least horrible design by Microsoft. The thing is, it has been like this for years and I don't see them fixing it :/

            https://stackoverflow.com/questions/61597263/office-365-xoauth2-for-imap-and-smtp-authentication-fails/61678485#61678485

            https://techcommunity.microsoft.com/t5/exchange/cannot-connect-to-imap-and-smtp-using-oauth2-0-to-exchange/m-p/1359651

            This is not the only thing we have been struggling with since the introduction of Graph and things being deprecated by it.

            @jerer

            To test this yourself you can unpack the plugin (cd to the plugin directory and run php -r '$phar = new Phar("auth-oauth2.phar"); $phar->extractTo("./auth-oauth2");'), edit the auth-oauth2/oauth2.php file, and update the callback() method for class OAuth2EmailAuthBackend to the following:

                public function callback($resp, $ref=null) {
                    $errors = [];
                    $err = sprintf('%s_auth_bk', $this->account->getType());
                    try {
                        // MOD
                        //if ($this->getState() == $resp['state']
                        //        && ($token=$this->getAccessToken($resp['code']))
                        //        && ($owner=$this->client->getResourceOwner($token))
                        //        && ($attrs=$this->mapAttributes($owner->toArray()))) {
                        if ($this->getState() == $resp['state']
                                && ($token=$this->getAccessToken($resp['code']))) {
                            $this->resetState();
                            $info =  [
                                'access_token' => $token->getToken(),
                                'refresh_token' => $token->getRefreshToken(),
                                'expires' => $token->getExpires(),
                                'resource_owner_id' => $token->getResourceOwnerId(),
                                //'resource_owner_email' => $attrs['email'],
                                'resource_owner_email' => $this->getEmailAddress(),
                            ];
            /*
                            if (!isset($attrs['email']))
                                $errors[$err] = $this->error_msg(self::ERR_EMAIL_ATTR, $attrs);
                            elseif (!$info['refresh_token'])
                                $errors[$err] = $this->error_msg(self::ERR_REFRESH_TOKEN);
                            elseif (!$this->signIn($attrs)) {
                                // On strict mode email mismatch is an error, otherwise
                                // set email address being authorized as the resource
                                // owner - with the assumption that a global admin
                                // authorized the account.
                                if ($this->isStrict())
                                    $errors[$err] = $this->error_msg(self::ERR_EMAIL_MISMATCH, $attrs);
                                else
                                    $info['resource_owner_email'] = $this->getEmailAddress();
                            }
            */
                            if (!$info['refresh_token'])
                                $errors[$err] = $this->error_msg(self::ERR_REFRESH_TOKEN);
                            // END
            
                            // Update the credentials if no validation errors
                            if (!$errors
                                    && !$this->updateCredentials($info, $errors)
                                    && !isset($errors[$err]))
                                 $errors[$err] = $this->error_msg(self::ERR_UNKNOWN);
                        }
                    } catch (Exception $ex) {
                        $errors[$err] =  $ex->getMessage();
                    }
            
                    // stash the results before redirecting
                    $email = $this->getEmail();
                    // TODO: check if email implements StashableTrait
                    if ($errors)
                        $email->stash('errors', $errors);
                    else
                        $email->stash('notice', sprintf('%s: %s',
                                    $this->account->getType(),
                                    __('OAuth2 Authorization Successful')
                                    ));
                    // redirect back to email page
                    $this->onSignIn();
                }

            Then login to the database, go to the _plugin table, modify your OAuth2 plugin record, set the install_path to plugins/auth-oauth2 (just remove the .phar), and set isphar to 0. Now the system will use the unpacked plugin with the custom changes.

            With the above changes applied the system will skip the user endpoint altogether during token retrieval. You will then get a token successfully (as previously) but then when you try to authenticate using that token you are given it doesn't work (go figure).

            Cheers.

              KevinTheJedi
              This is weird, things work fine for me at the moment (after removing the call to the user endpoing API). Did you forget some other scopes there? (like openid, User.Read, etc.).

              Can only use offline_access and https://outlook.office.com/XXXXXX scopes or IMAP/SMTP/POP authentication fails.