Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Office 365 OAUTH2 #250

Open
gtech99 opened this issue Nov 17, 2020 · 220 comments
Open

Office 365 OAUTH2 #250

gtech99 opened this issue Nov 17, 2020 · 220 comments
Assignees

Comments

@gtech99
Copy link

gtech99 commented Nov 17, 2020

Since Office 365 stopped supporting Basic Auth, can the code for Google OAUTH2 be applied to Office 365 OAUTH logins ?

@gilleslamiral
Copy link
Member

I don't know if imapsync Google OAUTH2 allows OAUTH2 for Office365 but I guess it doesn't work at all.
I'll will work on OAUTH2 for Office365 since I also plan to do it also for personal Google OAUTH2, which doesn't work for now with imapsync.
Keep in touch.

@MdeVries86
Copy link

I'm willing to test with my office 365 tennant.
I'm also willing to look into the implementation, but since I have almost no Perl experience, I'm not sure if it would be useful :)

@Andre0711er
Copy link

Hi.
Did someone has any news for that?
I need to migrate to this before October 2021 is coming.

@gilleslamiral
Copy link
Member

I'll try to implement this this year 2021, thanks to encourage me

@kimpenhaus
Copy link

if you need more beta-testers, I would throw my setup into the ring. currently using the docker image... google syncing works perfect 👍🏼 just waiting for the office 365 oauth integration.

thanks mate - for all the time you've invested!

@gilleslamiral
Copy link
Member

Hi Marcus!

Thanks for your proposal. The basic OAUTH2 code is written now. It assumes you have already the access token. I haven't tested it yet on Office365 but since it is the protocol it should work. Tell me. Release 2.216 is there:
https://imapsync.lamiral.info/imapsync
I haven't uploaded it to the dockerhub yet. Tell me if you need to.

https://imapsync.lamiral.info/imapsync

 --oauthaccesstoken1 str : The access token to authenticate with OAUTH2.
                       It will be combined with the --user1 value to form the 
                       string to pass with XOAUTH2 authentication.
                       The password given by --password1 or --passfile1
                       is ignored.
                       Instead of the access token itself, the value can be a
                       file containing the access token on the first line.
                       If the value is a file, imapsync reads its first line
                       and take this line as the access token. The advantage
                       of the file is that if the access token changes then
                       imapsync can read it again when it needs to reconnect 
                       during a run.


 --oauthaccesstoken2 str : same thing as --oauthaccesstoken1 

 --oauthdirect1 str  : The direct string to pass with XOAUTH2 authentication.
                       The password given by --password1 or --passfile1 and 
                       the user given by --user1 are ignored.

 --oauthdirect2 str  : same thing as oauthdirect1

Another point. Since you talk about a successful Gmail OAUTH2 with an old imapsync it may signify you have globally authenticated gmail users, ie as an admin. This is not available for Office365. A big complication for admins, I quote
https://docs.microsoft.com/en-us/exchange/client-developer/legacy-protocols/how-to-authenticate-an-imap-pop-smtp-application-by-using-oauth :

Get an access token
...
OAuth access to IMAP, POP, SMTP AUTH protocols via OAuth2 client credentials grant flow is not supported." 

@kimpenhaus
Copy link

Hi @gilleslamiral,

that sounds awesome - thanks for your effort and time invested! If you don't mind it would be perfect to push an image update to docker hub - as that gets automatically updated in my environment.

I've read about the admin limitation already before - I don't think I will run into that issue as I tried to authorize through Thunderbird in parallel to imapsync (I think it's inside your FAQs to verify it's not a general issue) and Thunderbird authorized through OAuth2.

Not sure about the access token yet - but I will figure out and will let you know if all works!

Thanks again!

@gilleslamiral
Copy link
Member

it would be perfect to push an image update to docker hub

Done imapsync release 2.143 https://hub.docker.com/r/gilleslamiral/imapsync/

Not sure about the access token yet

In Thunderbird, the password stored is the refresh token. Combined with the Thunderbird client_id and perhaps client_secret, it
can be used to generate a new access token, available one hour usually. This access token can then be used with any imap client like imapsync.

There is also a client_id and client_secret for imapsync and a I wrote a shell script to use them to get a refresh token and regenerate access tokens.

@Yannik
Copy link

Yannik commented Jun 12, 2022

@gilleslamiral Where may one find the client_id/client_secret for imapsync and said shell script?

@gilleslamiral
Copy link
Member

@nunomdmgoncalves
Copy link

Hi Gilles, any news on using oauth2 to authenticate imapsync in order to migrate mailboxes to office365 ?
thanks

@kayvanaarssen
Copy link

Same issue here, any news on OAuth2 for Office365

@Yannik
Copy link

Yannik commented Jun 27, 2022

It works fine. You just need to obtain the oauth token manually.

Method 1: Using mutt_oauth2
wget https://gitlab.com/muttmua/mutt/-/raw/master/contrib/mutt_oauth2.py

change:


ENCRYPTION_PIPE = ['gpg', '--encrypt', '--recipient', 'YOUR_GPG_IDENTITY']
DECRYPTION_PIPE = ['gpg', '--decrypt']
->
ENCRYPTION_PIPE = ['tee']
DECRYPTION_PIPE = ['tee']

        'redirect_uri': 'https://login.microsoftonline.com/common/oauth2/nativeclient',
->
        'redirect_uri': 'http://localhost/',

        'client_id': '',
        'client_secret': '',
->
        'client_id': '08162f7c-0fd2-4200-a84a-f25a4db0b584',
        'client_secret': 'TxRBilcHdC6WGBee]fs?QR:SJ8nI[g82',

(from thunderbird, see https://hg.mozilla.org/comm-central/file/tip/mailnews/base/src/OAuth2Providers.jsm)
Note: "You will want to check the current values in the source code. These secrets do not live longer than 24 months, so depending on when you read this the actual client_secret is likely different."

Run
python mutt_oauth2.py TOKEN_FILENAME2 --verbose --authorize --authflow localhostauthcode # when running on local system
or
python mutt_oauth2.py TOKEN_FILENAME2 --verbose --authorize --authflow authcode # when running on remote system
in that case, paste value from "code" from address bar. NOTE: make sure to not accidentally copy the "session_state" parameter as well.

Source:
https://www.vanormondt.net/~peter/blog/2021-03-16-mutt-office365-mfa.html
http://pnijjar.freeshell.org/2022/mutt-uw-duo/
https://gitlab.com/muttmua/mutt/-/blob/master/contrib/mutt_oauth2.py.README

Method 2: Powershell

Import-Module MSAL.PS -MaximumVersion 4.36.1.2 -AcceptLicense # NOTE: newer versions are apparantly broken
Clear-MsalTokenCache
$clientID = "08162f7c-0fd2-4200-a84a-f25a4db0b584" #thunderbird, see https://hg.mozilla.org/comm-central/file/tip/mailnews/base/src/OAuth2Providers.jsm
$secret = ConvertTo-SecureString 'TxRBilcHdC6WGBee]fs?QR:SJ8nI[g82' -AsPlainText -Force

$TenantId = "TENANTNAME.onmicrosoft.com"
$scope = "https://graph.microsoft.com/.default"
$myAccessToken = Get-MsalToken -ClientId $clientID `
         -TenantId $tenantID `
         -Scopes "$($scope)" `
         -clientsecret $secret
$myAccessToken.AccessToken

Source: https://techcommunity.microsoft.com/t5/teams-developer/authenticating-with-an-access-token-connect-microsoftteams/m-p/2233794/page/5

@kayvanaarssen
Copy link

kayvanaarssen commented Jun 27, 2022

@Yannik Thanks for the info; now i get;

invalid_client
AADSTS700025: Client is public so neither 'client_assertion' nor 'client_secret' should be presented.
Trace ID: 8dbea256-0990-42fe-a140-83bc1f636c00
Correlation ID: 1855007f-2993-4f90-8912-9922abd157e3
Timestamp: 2022-06-27 22:21:14Z

Fixed now Created a new Application for it, maybe i messed to much with the old one.

But what is now the best command to use in the imapsync?
I now get errors like;

Host2: found ID capability. Sending/receiving ID, presented in raw IMAP for now.
In order to avoid sending/receiving ID, use option --noid
Sending: 4 ID ("name" "imapsync" "version" "2.148" "os" "linux" "vendor" "Gilles LAMIRAL" "support-url" "https://imapsync.lamiral.info/" "date" "22-Jul-2021 14:21:09 +0000" "side" "host2")
Sent 181 bytes
Read: 	4 BAD User is authenticated but not connected.
ERROR: 4 BAD User is authenticated but not connected. at /usr/share/perl5/vendor_perl/Mail/IMAPClient.pm line 1364.
	Mail::IMAPClient::__ANON__('4 BAD User is authenticated but not connected.\x{d}\x{a}') called at /usr/share/perl5/vendor_perl/Mail/IMAPClient.pm line 1400
	Mail::IMAPClient::_get_response('Mail::IMAPClient=HASH(0x29fc7a0)', 4, undef) called at /usr/share/perl5/vendor_perl/Mail/IMAPClient.pm line 1326
	Mail::IMAPClient::_imap_command_do('Mail::IMAPClient=HASH(0x29fc7a0)', 'ID ("name" "imapsync" "version" "2.148" "os" "linux" "vendor"...') called at /usr/share/perl5/vendor_perl/Mail/IMAPClient.pm line 1225

./imapsync --addheader --automap --host1 mail.server.nl --host2 outlook.office365.com --office2 --password1 '' --password2 '' --user1 USER@DOMAIN --user2 USER@DOMAIN --oauthaccesstoken2 tokenfile1

The Access Key that i got from the Python script is in the tokenfile1

____ Update 28-06 _____

Got it working!
I've used the Admin (Global Admin) Mail Account in the Python script.
But I looked at it this morning after some sleep and tried the user that I wanted to migrate, and that worked :-D

So got it working! Thanks

@alfonsrv
Copy link

alfonsrv commented Aug 3, 2022

The OAuth2 procedure is a nightmare. Even after investing multiple hours into it, I simply couldn't get it to work.

I wish I never went down that rabbit hole which the docs lead me to believe was the only way to make it work. While in fact, BASIC IMAP authentication can simply be re-enabled and works without any issues using username and password.

Here's the Python code I came up with for anyone trying to get the OAuth2 nightmare to work:

import base64
import imaplib
from time import sleep

import requests

MAIL = 'migrate@domain.tld'
SERVER = 'outlook.office365.com'

# OAuth2 stuff
AUTH_URL = 'https://login.microsoftonline.com'
TENANT_ID = ''
CLIENT_ID = ''  # application client id


def test_imap(auth_string):
    imap_conn = imaplib.IMAP4_SSL(SERVER)
    imap_conn.debug = 10
    imap_conn.authenticate('XOAUTH2', lambda x: auth_string.encode())
    imap_conn.select('INBOX')
    imap_conn.list()


def generate_xoauth2(username: str, access_token: str, base64_encode: bool = True) -> str:
    """ Generates XOauth2 String """
    auth_string = f'user={username}\1auth=Bearer {access_token}\1\1'
    if base64_encode: auth_string = base64.b64encode(auth_string.encode()).decode()
    return auth_string


def device_auth_initiate() -> str:
    data = {
        'scope': 'user.read offline_access email openid profile https://outlook.office.com/IMAP.AccessAsUser.All https://outlook.office.com/POP.AccessAsUser.All https://outlook.office.com/SMTP.Send',
        'client_id': CLIENT_ID
    }
    r = requests.post(f'{AUTH_URL}/{TENANT_ID}/oauth2/v2.0/devicecode', data=data)
    response = r.json()
    print(response.get('message'))
    return response.get('device_code')


def device_auth_acquire(device_code):
    data = {
        'grant_type': 'urn:ietf:params:oauth:grant-type:device_code',
        'code': device_code,
        'client_id': CLIENT_ID
    }
    while True:
        print('Polling M365 Graph API for successful authentication...')
        r = requests.post(f'{AUTH_URL}/{TENANT_ID}/oauth2/v2.0/token', data=data)
        response = r.json()
        if response.get('refresh_token'):
            print('Successfully authenticated M365 user!')
            return response.get('access_token'), response.get('refresh_token')
        sleep(10)


if __name__ == '__main__':
    device_code = device_auth_initiate()
    access_token, _ = device_auth_acquire(device_code)
    auth_string = generate_xoauth2(MAIL, access_token, base64_encode=False)
    print(auth_string)
    test_imap(auth_string)

@kayvanaarssen
Copy link

@alfonsrv Did you get it to work?
I've used it now multiple times with success.
I Agree there needs to be a better / simpeler solution but someone has to create a script / implementation for IMAP SYNC for it... Until then the Python script is the best way to go.

@alfonsrv
Copy link

alfonsrv commented Aug 4, 2022

No. Not sure which part is not working; not errors showing up in the Sign-in logs – I tried both registering my own Azure app as well as using the Thunderbird Azure app, but it simply doesn't work.

Using username + password now. 👍🏼

edit: Just checked again – the main reason it didn't work was because I thought the data has to be Base64 encoded separately, while in fact imaplib's authenticate() does that for you automatically. Got XOAuth2 to work on M365 with my code above.

@madmudklip
Copy link

@alfonsrv having the exact same issue and tried your code above with no luck. Could you please share what you did to get it working as setting base64encode to false doesn't seem to do the trick. Would be very much appreciated!

@alfonsrv
Copy link

@madmudklip should work like that. Make sure:

  • your app has the required permissions (stated below)
  • tenant id + client id (from M365 app) variables are set properly in the Python script
  • client credential flow is activated in your M365 app (required for device auth)

Permissions:

@madmudklip
Copy link

@alfonsrv
Thanks for the reply! Got it working, was just missing the offline_access permission.
Planning on just using the refresh token to keep reissuing bearer for the app lifetime, seems like it should work as what I could find states that the refresh gets extended as it gets used, so fingers crossed. This has been a pain to get sorted! Just need to buy some time with IMAP as basic auth is dead and we are looking to transition over to using graph.

@alfonsrv
Copy link

alfonsrv commented Aug 30, 2022

@madmudklip sure! Can also drop a quick refresh token function if you need it – already implemented it somewhere before.
Basic auth is not really dead. It can easily be reactivated, but somehow only via the GUI and not over PowerShell. Which saying out loud sounds ridiculous (as we're still talking about Microsoft here), but from what I experienced couldn't get it to work any other way.

@ThiefMaster
Copy link

so oauth itself isn't that bad - using mutt_oauth2.py saves you a lot of time.

however the main issue is that at least office365's IMAP server terminates your existing connection when the token expires. so a biggersync taking more than ~75 minutes needs to be restarted every 75 minutes with a refreshed token...

@adrensnyder
Copy link

adrensnyder commented Oct 6, 2022

Hello,
i cannot get imapsync to connect to a 365 account. I retrieve the token from the powershell script

/usr/bin/imapsync -addheader --automap --disarmreadreceipts --office2
--host1 mail.orighost.com --user1 "user@orighost.com" --password1 "XXX" --ssl1 --notls1
--host2 outlook.office365.com --user2 "user@domain.onmicrosoft.com" --oauthaccesstoken2 tokenfile2 --password2 "XXX"

The Token is contained in the file "tokenfile2"

I get always the error:
Host2: connecting and login on host2 [outlook.office365.com] port [993] with user [user@domain.onmicrosoft.com]
Host2 IP address: XX.XX.XX.XX Local IP address: XX:XX.XX.XX
Host2 banner: * OK The Microsoft Exchange IMAP4 service is ready. [RgBSADAAUAAyADgAMQBDAEEAMAAwADcAMAAuAEQARQBVAFAAMgA4ADEALgBQAFIATwBEAC4ATwBVAFQATABPAE8ASwAuAEMATwBNAA==]
Host2 capability before authentication: IMAP4 IMAP4rev1 AUTH=PLAIN AUTH=XOAUTH2 SASL-IR UIDPLUS ID UNSELECT CHILDREN IDLE NAMESPACE LITERAL+
Host2 failure: Error login on [outlook.office365.com] with user [user@domain.onmicrosoft.com] auth [XOAUTH2 accesstoken]: 2 NO AUTHENTICATE failed.
Host2: failed login on [outlook.office365.com] with user [user@domain.onmicrosoft.com] auth [XOAUTH2 accesstoken]

Any suggestion?

EDIT:
Now i get "Read: 21 BAD User is authenticated but not connected".
I will test in next days but i think isn't working. Maybe i miss something yet

EDIT2:
Solved finally. I've to use a license for my admin user and use it with --authuserX. Obviously assign permissions for the destination mail
--host2 outlook.office365.com --authuser2 "admin@domain.com" --user2 "test@domain.com" --oauthaccesstoken2 tokenfile2 --password2 "xxx"

@adrensnyder
Copy link

adrensnyder commented Oct 6, 2022

so oauth itself isn't that bad - using mutt_oauth2.py saves you a lot of time.

however the main issue is that at least office365's IMAP server terminates your existing connection when the token expires. so a biggersync taking more than ~75 minutes needs to be restarted every 75 minutes with a refreshed token...

2 months ago i've used mutt to get the token but now with the same settings in another tenant i cannot get it working.
Obviously i've created an App in the new tenant with id and secret. I'm using a user with Global permissions.

I'm using this settings:
{"registration": "microsoft", "authflow": "localhostauthcode", "email": "admin@domain.onmicrosoft.com", "access_token": "", "access_token_expiration": "", "refresh_token": ""}

Everytime i start the script it return me a string to be used in the web. I retrieve form the page the link http://localhost:XXXXX and connect to it to authorize.

I get:
Visit displayed URL to authorize this application. Waiting...127.0.0.1 - - [06/Oct/2022 16:10:22] "GET / HTTP/1.0" 200 -
Did not obtain an authcode.

I'm using the file mutt_oauth2.py with
ENCRYPTION_PIPE = ['tee']
DECRYPTION_PIPE = ['tee']
'redirect_uri': 'http://localhost/',
Correct client_id and client_secret (Same that it's working in the powershell script"

Do you use different settings?

EDIT:
Problem solved recreating the App in Azure.

@blu-IT
Copy link

blu-IT commented Nov 21, 2022

--oauthaccesstoken1 str : The access token to authenticate with OAUTH2.
It will be combined with the --user1 value to form the
string to pass with XOAUTH2 authentication.
The password given by --password1 or --passfile1
is ignored.
Instead of the access token itself, the value can be a
file containing the access token on the first line.
If the value is a file, imapsync reads its first line
and take this line as the access token. The advantage
of the file is that if the access token changes then
imapsync can read it again when it needs to reconnect
during a run.

--oauthaccesstoken2 str : same thing as --oauthaccesstoken1

--oauthdirect1 str : The direct string to pass with XOAUTH2 authentication.
The password given by --password1 or --passfile1 and
the user given by --user1 are ignored.

--oauthdirect2 str : same thing as oauthdirect1

Hi,

can somebody point me to where I get / can configure the oauthaccestoken inside Admin Center 365)

Thanks!

@adrensnyder
Copy link

adrensnyder commented Nov 21, 2022

--oauthaccesstoken1 str : The access token to authenticate with OAUTH2.
It will be combined with the --user1 value to form the
string to pass with XOAUTH2 authentication.
The password given by --password1 or --passfile1
is ignored.
Instead of the access token itself, the value can be a
file containing the access token on the first line.
If the value is a file, imapsync reads its first line
and take this line as the access token. The advantage
of the file is that if the access token changes then
imapsync can read it again when it needs to reconnect
during a run.
--oauthaccesstoken2 str : same thing as --oauthaccesstoken1
--oauthdirect1 str : The direct string to pass with XOAUTH2 authentication.
The password given by --password1 or --passfile1 and
the user given by --user1 are ignored.
--oauthdirect2 str : same thing as oauthdirect1

Hi,

can somebody point me to where I get / can configure the oauthaccestoken inside Admin Center 365)

Thanks!

Open Azure
https://portal.azure.com/
Click App Registrations and New Registration (Or search for it in the new UI)
Give a name and select "Accounts in any organization directory (any Azure AD directory - Multi-tenant)"
Select Mobile and Desktop Applications - http://localhost/
Copy the "Application ID (client)" of the new app you've created

Click on Authentication on the left
Select Allow public client flows

Click on API Permissions (Always in the App Registration section)
Click on "Add authorization"
Click on "APIs used by your organization" and select "Microsoft Graph" (Use "load other" if you can't find it)
Click on "Application Permissions"
Select "Delegated Permissions"
Add permissions

  • IMAP.AccessAsUser
  • POP.AccessAsUser.All
  • SMTP.Send
  • offline_access
  • User.Read

Then click on "Grant administrator consent for XXX"

I've the panel in Italian language so i've traduced them.
I'm not sure that is the correct translation

@blu-IT
Copy link

blu-IT commented Nov 22, 2022

@adrensnyder

Grazie! Potevi anche rispondere in italiano... capivo... ;-)

Thanks a lot! Do I have to create an accesstoken for every user I want to sync or can I create some kind of "masteraccess"?

@akops76
Copy link

akops76 commented Sep 23, 2023

Do you run oauth2_office365_with_imap where you run the browser?

I performed the below steps in a centos 7 VM (through ssh connection):

Why can't you run oauth2_office365_with_imap where you run the browser?

For the migration i use a centos 7 VM server, and we dont install GUI on our servers. Just command line!!! So running a browser in the VM is not an option.

  1. Edit the `oauth2_office365_with_imap script and change the variables: redirect_uri , client_id & client_secret.
    To redirect_uri i set it to "http://localhost". To the other two variables i used the values from the azure app that i already had.

Ok.

  1. run the command: ./oauth2_office365_with_imap testfaculty@mydomain.com "" localhost
  2. on terminal the above script displayed a very long url (px https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client....................).
  3. I put the very long url, in a browser on my PC and i logged in my tenant with the credentials of the user: testfaculty@mydomain.com
  4. After that, i saw the error about the localhost on my browser.
  5. In the terminal the message displayed is: "Then, after the authentication is finished, press ENTER: "
    If i press ENTER the below messages is shown:
    "Thanks. Now I try to collect the code
    No code from https://imapsync.lamiral.info/imapsync_auth/ozbasbaamkpomvgakqwmvfeeijokrnzq : 404 Not Found
    Failed to collect the code"

"No code from https://imapsync.lamiral.info/imapsync_auth/ozb..." means you didn't run fully the localhost option like this:

./oauth2_office365_with_imap testfaculty@mydomain.com "" localhost

I run the command exactly as you wrote it..

Anyway thanks for your help. As the method of [ChilledCucumber], for creating an access & refresh token is working fine for me, i will stick with his method.

I will also try the https://imapsync.lamiral.info/imapsync version to solve the problem of re-reading the token file.
Even if this version work ok , I will try to convince my organization to buy the software.

akops76

@gilleslamiral
Copy link
Member

Why can't you run oauth2_office365_with_imap where you run the browser?

For the migration i use a centos 7 VM server, and we dont install GUI on our servers. Just command line!!! So running a browser in the VM is not an option.

Ok.
This is not what I asked.

"No code from https://imapsync.lamiral.info/imapsync_auth/ozb..." means you didn't run fully the localhost option like this:

./oauth2_office365_with_imap testfaculty@mydomain.com "" localhost

I run the command exactly as you wrote it..

That's strange. What release did you use? The current is 1.24 since 2023/07/18
https://imapsync.lamiral.info/oauth2/oauth2_office365/oauth2_office365_with_imap

Anyway thanks for your help. As the method of [ChilledCucumber], for creating an access & refresh token is working fine for me, i will stick with his method.

Ok, good.
The funny thing is that I wrote oauth2_office365_with_imap because I couldn't do it the Mutt way...

@silicooon
Copy link

Hello @gilleslamiral and thanks for giving oauth2 a tweak like this.
I have worked with the mutt way but I would really like to test this way with oauth2_office365_with_imap as well.

I am having this below error on archlinux and MacOS that I tried it so far.
Can't locate HTTP/Daemon/SSL.pm in @INC (you may need to install the HTTP::Daemon::SSL module) (@INC contains: /Library/Perl/5.30/darwin-thread-multi-2level /Library/Perl/5.30 /Network/Library/Perl/5.30/darwin-thread-multi-2level /Network/Library/Perl/5.30 /Library/Perl/Updates/5.30.2 /System/Library/Perl/5.30/darwin-thread-multi-2level /System/Library/Perl/5.30 /System/Library/Perl/Extras/5.30/darwin-thread-multi-2level /System/Library/Perl/Extras/5.30) at ./oauth2_office365_with_imap line 16. BEGIN failed--compilation aborted at ./oauth2_office365_with_imap line 16.

Is there some package missing?
Thanks in advance!

@gilleslamiral
Copy link
Member

Can't locate HTTP/Daemon/SSL.pm

In oauth2_office365_with_imap, comment the line;

 use HTTP::Daemon::SSL ;

@silicooon
Copy link

Oh thank you! Just tried it.

./oauth2_office365_with_imap user@domain.com "" localhost Can't locate Mail/IMAPClient.pm in @INC (you may need to install the Mail::IMAPClient module) (@INC contains: /Library/Perl/5.30/darwin-thread-multi-2level /Library/Perl/5.30 /Network/Library/Perl/5.30/darwin-thread-multi-2level /Network/Library/Perl/5.30 /Library/Perl/Updates/5.30.2 /System/Library/Perl/5.30/darwin-thread-multi-2level /System/Library/Perl/5.30 /System/Library/Perl/Extras/5.30/darwin-thread-multi-2level /System/Library/Perl/Extras/5.30) at ./oauth2_office365_with_imap line 25. BEGIN failed--compilation aborted at ./oauth2_office365_with_imap line 25.

More I have to install?

@silicooon
Copy link

It worked after I comment the line.
use Mail::IMAPClient module

I got the token but then it errors with this
Can't locate object method "new" via package "Mail::IMAPClient" (perhaps you forgot to load "Mail::IMAPClient"?) at ./oauth2_office365_with_imap line 490.

@gilleslamiral
Copy link
Member

It worked after I comment the line. use Mail::IMAPClient module

I got the token but then it errors with this Can't locate object method "new" via package "Mail::IMAPClient" (perhaps you forgot to load "Mail::IMAPClient"?) at ./oauth2_office365_with_imap line 490.

So, it didn't work. It's because use Mail::IMAPClient is needed

@silicooon
Copy link

All ok after cpan install Mail::IMAPClient
Thank you so much for making this :)

@gilleslamiral
Copy link
Member

`./oauth2_office365_with_imap user@domain.com "" localhost Can't locate Mail/IMAPClient.pm in @inc (you may need to install the Mail::IMAPClient module)

More I have to install?

Install the Mail::IMAPClient module

Install imapsync,

@silicooon
Copy link

cpan install Mail::IMAPClient was the only thing I was missing on macos Big Sur with brew installed.
Thanks again!

@gilleslamiral
Copy link
Member

cpan install Mail::IMAPClient was the only thing I was missing on macos Big Sur with brew installed.

You don't use imapsync?

@silicooon
Copy link

silicooon commented Oct 11, 2023

cpan install Mail::IMAPClient was the only thing I was missing on macos Big Sur with brew installed.

You don't use imapsync?

Of course I use imapsync, but I was missing IMAPClient..

@celevra
Copy link

celevra commented Oct 18, 2023

i use the version v 1.25 2023/10/12 12:08:11

but something seems not right:

Started at Wed Oct 18 17:04:10 2023
Using Mail::IMAPClient version 3.43 on perl 5.030000
Connecting with IO::Socket::SSL PeerAddr outlook.office365.com PeerPort 993 Proto tcp Timeout 600 Debug 1
Connected to outlook.office365.com
Read:   * OK The Microsoft Exchange IMAP4 service is ready. [RgBSADUAUAAyADgAMQBDAEEAMAAwADUAMgAuAEQARQBVAFAAMgA4ADEALgBQAFIATwBEAC4ATwBVAFQATABPAE8ASwAuAEMATwBNAA==]
Sending: 1 AUTHENTICATE XOAUTH2
Sent 24 bytes
Read:   +
Sending: [Redact: Count=1 Showcredentials=OFF]
Sent 3002 bytes
Read:   1 OK AUTHENTICATE completed.
Sending: 2 LIST "" *
Sent 13 bytes
Read:   2 BAD User is authenticated but not connected.
ERROR: 2 BAD User is authenticated but not connected. at /usr/local/share/perl/5.30.0/Mail/IMAPClient.pm line 1388.
        Mail::IMAPClient::__ANON__("2 BAD User is authenticated but not connected.\x{d}\x{a}") called at /usr/local/share/perl/5.30.0/Mail/IMAPClient.pm line 1424
        Mail::IMAPClient::_get_response(Mail::IMAPClient=HASH(0x563436d87a70), 2, undef) called at /usr/local/share/perl/5.30.0/Mail/IMAPClient.pm line 1350
        Mail::IMAPClient::_imap_command_do(Mail::IMAPClient=HASH(0x563436d87a70), "LIST \"\" *") called at /usr/local/share/perl/5.30.0/Mail/IMAPClient.pm line 1248
        Mail::IMAPClient::_imap_command(Mail::IMAPClient=HASH(0x563436d87a70), "LIST \"\" *") called at /usr/local/share/perl/5.30.0/Mail/IMAPClient.pm line 679
        Mail::IMAPClient::_list_or_lsub(Mail::IMAPClient=HASH(0x563436d87a70), "LIST", undef, undef) called at /usr/local/share/perl/5.30.0/Mail/IMAPClient.pm line 685
        Mail::IMAPClient::list(Mail::IMAPClient=HASH(0x563436d87a70), undef, undef) called at /usr/local/share/perl/5.30.0/Mail/IMAPClient.pm line 723
        Mail::IMAPClient::_folders_or_subscribed(Mail::IMAPClient=HASH(0x563436d87a70), "list", undef) called at /usr/local/share/perl/5.30.0/Mail/IMAPClient.pm line 745
        Mail::IMAPClient::folders(Mail::IMAPClient=HASH(0x563436d87a70)) called at ./oauth2_office365_with_imap line 508
        main::oauth2_check_imap_access(HASH(0x563436a54890)) called at ./oauth2_office365_with_imap line 99
        main::oauth2_approval(HASH(0x563436a54890)) called at ./oauth2_office365_with_imap line 39
ERROR: 2 BAD User is authenticated but not connected. at /usr/local/share/perl/5.30.0/Mail/IMAPClient.pm line 1298.
        Mail::IMAPClient::_imap_command(Mail::IMAPClient=HASH(0x563436d87a70), "LIST \"\" *") called at /usr/local/share/perl/5.30.0/Mail/IMAPClient.pm line 679
        Mail::IMAPClient::_list_or_lsub(Mail::IMAPClient=HASH(0x563436d87a70), "LIST", undef, undef) called at /usr/local/share/perl/5.30.0/Mail/IMAPClient.pm line 685
        Mail::IMAPClient::list(Mail::IMAPClient=HASH(0x563436d87a70), undef, undef) called at /usr/local/share/perl/5.30.0/Mail/IMAPClient.pm line 723
        Mail::IMAPClient::_folders_or_subscribed(Mail::IMAPClient=HASH(0x563436d87a70), "list", undef) called at /usr/local/share/perl/5.30.0/Mail/IMAPClient.pm line 745
        Mail::IMAPClient::folders(Mail::IMAPClient=HASH(0x563436d87a70)) called at ./oauth2_office365_with_imap line 508
        main::oauth2_check_imap_access(HASH(0x563436a54890)) called at ./oauth2_office365_with_imap line 99
        main::oauth2_approval(HASH(0x563436a54890)) called at ./oauth2_office365_with_imap line 39
Folders found: .

Success IMAP login to account

@gilleslamiral
Copy link
Member

gilleslamiral commented Oct 26, 2023

Hi @krull

#250 (comment)

I have a clue now.
You were in a docker context so the file TOKEN.txt is not available for imapsync when imapsync runs, it can't open it, it doesn't exist in the docker context, so imapsync uses the string "TOKEN.txt" as the token and fails.
With $(cat TOKEN.txt), the shell opens the file and gives the content to imapsync.

What I don't understand is how the docker is run?

Here are the runs as per request with --showpasswords (sanitized for posting):

Run with --oauthaccesstoken2 TOKEN.txt \ (NO AUTHENTICATE failed)

~/syncfiles $ /home/venv/.venv/bin/imapsync ... --oauthaccesstoken2 TOKEN.txt 
Docker context detected with the file /.dockerenv

Run with --oauthaccesstoken2 $(cat TOKEN.txt) \ (state Authenticated)

~/syncfiles $ /home/venv/.venv/bin/imapsync ... --oauthaccesstoken2 $(cat TOKEN.txt) 

TOKEN.txt is being written with refresh.py without issues now since yesterday's with the hourly interval. Also just to rule out permissions I have set it's chmod to 777.

Hope this helps.

@krull

@gilleslamiral
Copy link
Member

gilleslamiral commented Oct 27, 2023

#250 (comment)

Is it possible to add a new parameter like --oauthtokenrefreshcmd1 /script/to/run/for/generatetoken.sh (and --oauthtokenrefreshcmd2 /script/to/run/for/generatetoken.sh) and that this script is started before you do the reconnect (when it is set) ? In that case no timer script is needed and everyone can use his own token generate script. That would be a nice feature.

Imapsync release 2.268 added this

 --oauthrefreshcmd1 str : An optional command to call, to refresh the host1
                          token before any oauth authentication.
                          It can have arguments like "cmd arg1 arg2 ..."

 --oauthrefreshcmd2 str : same thing as --oauthrefreshcmd1 but for host2.

Get it at
https://imapsync.lamiral.info/imapsync

@silicooon
Copy link

needed to install some modules but I am finally on 2.229 :) Thank you!

@gilleslamiral
Copy link
Member

needed to install some modules but I am finally on 2.229 :) Thank you!

2.229 is buggy...

@silicooon
Copy link

silicooon commented Oct 27, 2023 via email

@gilleslamiral
Copy link
Member

#250 (comment)

Best way to go back?

Why go back instead of going forward?

Imapsync release 2.268 :
https://imapsync.lamiral.info/imapsync

@silicooon
Copy link

DEBUG: .../IO/Socket/SSL.pm:1177: global error: Undefined SSL object
DEBUG: .../IO/Socket/SSL.pm:1177: global error: Undefined SSL object
Host2 folder old: Could not select: * BYE Connection closed. 14; 160 BAD User is authenticated but not connected.
DEBUG: .../IO/Socket/SSL.pm:1177: global error: Undefined SSL object
DEBUG: .../IO/Socket/SSL.pm:1177: global error: Undefined SSL object
Could not create folder [old/2018] from [old.2018]: * BYE Connection closed. 14; 163 BAD User is authenticated but not connected.
DEBUG: .../IO/Socket/SSL.pm:1177: global error: Undefined SSL object
DEBUG: .../IO/Socket/SSL.pm:1177: global error: Undefined SSL object
DEBUG: .../IO/Socket/SSL.pm:1177: global error: Undefined SSL object
DEBUG: .../IO/Socket/SSL.pm:1177: global error: Undefined SSL object
Host2 folder old/2018: Could not select: * BYE Connection closed. 14; 169 BAD User is authenticated but not connected.
ETA: Thursday 07 December 2023-12-07 01:07:32 +0200 EET  616731 s  7394/7394 msgs left

Tried it again today on fresh 365 tenant (account) but after using imapsync token way like i did on another tenant, i've started to get all those errors i've quoted above.
Is there some step missing? I've tried also from azure/entra to make the API/Application things but it's still no go.

Any help is much appreciate! Thanks in advance!

@silicooon
Copy link

Hello again :)
Is there any way I can have this token renewed even when I am not stopping it, and rerun it every time? (host1 imap host2 o365)
Also, is there a way to sync only the last two months of the user's inbox?
I have tried like: --search "SENTSINCE 1-Sep-2023 SENTBEFORE 2-Feb-2024"
but no luck so far. I am asking cause I have 2 really big mailboxes to sync like 55GB+ each.
Thanks in advance

@leonroy
Copy link

leonroy commented Feb 24, 2024

Hello again :) Is there any way I can have this token renewed even when I am not stopping it, and rerun it every time?

  • Download and extract the OAuth binary here: https://imapsync.lamiral.info/oauth2/
  • Create a script like refresh-access-token.sh - set the path to your oauth2_office365_with_imap location and set your O365 mailbox name:
#!/bin/sh

oauth2_office365/oauth2_office365_with_imap o365user@example.com
  • Then run imapsync with option: --oauthrefreshcmd2 "/var/tmp/oauth2_office365/refresh-access-token.sh" - it'll renew the token during running of the script

If using Docker you can do:

docker run --rm --platform linux/amd64 -v $(pwd)/tokens:/var/tmp/tokens \
-v $(pwd)/oauth2_office365:/var/tmp/oauth2_office365 gilleslamiral/imapsync imapsync \
--host1 "imap.gmail.com" --user1 "gmailuser@example.com" --gmail1 --password1 'super-secret1' \
--host2 "outlook.office365.com" --user2 "o365user@example.com" --office2 \
--oauthaccesstoken2  /var/tmp/tokens/oauth2_tokens_user@example.com.txt  \
--oauthrefreshcmd2 "/var/tmp/oauth2_office365/refresh-access-token.sh" --subfolder2 "my-gmail-import"

Edit: Actually scratch that, the oauthrefreshcmd2 doesn't appear to work and hangs on:

Executing script: /var/tmp/oauth2_office365/refresh-access-token.sh

@gilleslamiral
Copy link
Member

The shit it takes to make it work!
It's time I integrate the refreshing in imapsync...

@premax
Copy link

premax commented Mar 6, 2024

docker run --rm --platform linux/amd64 -v $(pwd)/tokens:/var/tmp/tokens \
-v $(pwd)/oauth2_office365:/var/tmp/oauth2_office365 gilleslamiral/imapsync imapsync \
--host1 "imap.gmail.com" --user1 "gmailuser@example.com" --gmail1 --password1 'super-secret1' \
--host2 "outlook.office365.com" --user2 "o365user@example.com" --office2 \
--oauthaccesstoken2  /var/tmp/tokens/oauth2_tokens_user@example.com.txt  \
--oauthrefreshcmd2 "/var/tmp/oauth2_office365/refresh-access-token.sh" --subfolder2 "my-gmail-import"

I couldn't get this to work. I have used this command:

docker run --rm --platform linux/amd64 -v $(pwd)/oauth2_office365/tokens:/var/tmp/oauth2_office365 gilleslamiral/imapsync imapsync --no-modulesversion --noreleasecheck --host1 imap.gmail.com --user1 'user@gsuite' --password1 'blah' --user2 'user@tenant.onmicrosoft.com' --office2 --oauthaccesstoken2 /var/tmp/oauth2_office365/oauth2_tokens_user@tenant.onmicrosoft.com.txt

The tokens file seems to be ignored and imapsync cannot authenticate to destination host.
I have done this workaround - script tenant.sh:

./oauth2_office365_with_imap user@tenant.onmicrosoft.com
read -r TOKEN < $(pwd)/tokens/oauth2_tokens_user@tenant.onmicrosoft.com.txt
docker run gilleslamiral/imapsync imapsync --no-modulesversion --noreleasecheck --host1 imap.gmail.com --user1 'user@gsuite' --password1 'blah' --user2 'user@tenant.onmicrosoft.com' --office2 --oauthaccesstoken2 $TOKEN

And it is working (until token is valid, that is ca 30-60 min).
So to make it more permanent I have done another script timeout.sh:

while :
do
        timeout 60m $1
done

And I am invoking it like this:

cd oauth2_office365
../timeout.sh ../tenant.sh

and it is quitting and restarting with fresh token every 1 hour.

@gilleslamiral
Copy link
Member

It looks like the token file is not generated. leonroy said:

Edit: Actually scratch that, the oauthrefreshcmd2 doesn't appear to work and hangs on:
Executing script: /var/tmp/oauth2_office365/refresh-access-token.sh

@krull
Copy link

krull commented Mar 13, 2024

Hey guys! Hope you're all doing good. 👍

So the O365 Global Admin for OAUTH2 still no good right?

I am in need to get the 1000s of mailboxes synced out of o365, and will be a pain with single User OAUTH2.

I tried to read up here, in adding another IMAP.AccessAsApp permission in portal.azure.com, however I am uncertain if that fixes the LIST command not working using a token from a Global Admin.

I am getting BAD User is authenticated but not connected. with this Global Admin Token still.

Anyone successfully used Global Admin Token? 🤔

@mschering
Copy link

mschering commented Mar 14, 2024

It worked fine for me using imapsync v2.277.

I received a user that has access to all mailboxes I need to migrate. I used this script:

https://imapsync.lamiral.info/oauth2/oauth2_office365/README.txt

I couldn't use the app from lamiral so we created our own app and updated the client id and credentials inside the script. The app had permissions IMAP.AccessAsApp and IMAP.AccessAsAll ( Actually not sure which one is required but both worked).

Then I ran the script and received tokens. I used this command on all of the mailboxes I needed to migrate:

/usr/local/bin/imapsync --syncinternaldates --office1 --oauthaccesstoken1 ./tokens/oauth2_tokens_ MASKED.txt --user1 MASKED --password1 MASKED --host2 MASKED --tls2 --user2 MASKED --password2 MASKED --subscribe --allowsizemismatch --nofoldersizes --sep1 / --sep2 . --regextrans2 s,/,_,g

Note that --user1 is the mailbox user and not the user that I used to create the oauth access token.

I hope this helps!

Good luck.
Merijn

@krull
Copy link

krull commented Mar 14, 2024

It worked fine for me using imapsync v2.277.

I received a user that has access to all mailboxes I need to migrate. I used this script:

https://imapsync.lamiral.info/oauth2/oauth2_office365/README.txt

I couldn't use the app from lamiral so we created our own app and updated the client id and credentials inside the script. The app had permissions IMAP.AccessAsApp and IMAP.AccessAsAll ( Actually not sure which one is required but both worked).

Then I ran the script and received tokens. I used this command on all of the mailboxes I needed to migrate:

/usr/local/bin/imapsync --syncinternaldates --office1 --oauthaccesstoken1 ./tokens/oauth2_tokens_ MASKED.txt --user1 MASKED --password1 MASKED --host2 MASKED --tls2 --user2 MASKED --password2 MASKED --subscribe --allowsizemismatch --nofoldersizes --sep1 / --sep2 . --regextrans2 s,/,_,g

Note that --user1 is the mailbox user and not the user that I used to create the oauth access token.

I hope this helps!

Good luck. Merijn

Thank you for this confirmation! 🥳

Will report back with my findings on IMAP.AccessAsApp and IMAP.AccessAsAll

Cheers @mschering

@krull
Copy link

krull commented Mar 14, 2024

I couldn't use the app from lamiral so we created our own app and updated the client id and credentials inside the script. The app had permissions IMAP.AccessAsApp and IMAP.AccessAsAll ( Actually not sure which one is required but both worked).

So I just tested IMAP.AccessAsApp, with my own App in portal.azure.com (updated client_id and client_secret in oauth2_office365_with_imap file), and still getting BAD User is authenticated but not connected.

Host1: found ID capability. Sending/receiving ID, presented in raw IMAP for now.
In order to avoid sending/receiving ID, use option --noid
Sending: 4 ID ("name" "imapsync" "version" "2.277" "os" "linux" "vendor" "Gilles LAMIRAL" "support-url" "https://imapsync.lamiral.info/" "date" "02-Jan-2024 16:04:36 +0000" "side" "host1")
Sent 181 bytes
Read:   4 BAD User is authenticated but not connected.
ERROR: 4 BAD User is authenticated but not connected. at ./lib/perl5/Mail/IMAPClient.pm line 1388.
        Mail::IMAPClient::__ANON__("4 BAD User is authenticated but not connected.\x{d}\x{a}") called at ./lib/perl5/Mail/IMAPClient.pm line 1424
        Mail::IMAPClient::_get_response(Mail::IMAPClient=HASH(0x7f628587e0e8), 4, undef) called at ./lib/perl5/Mail/IMAPClient.pm line 1350
        Mail::IMAPClient::_imap_command_do(Mail::IMAPClient=HASH(0x7f628587e0e8), "ID (\"name\" \"imapsync\" \"version\" \"2.277\" \"os\" \"linux\" \"vendor\""...) called at ./lib/perl5/Mail/IMAPClient.pm line 1248
        Mail::IMAPClient::_imap_command(Mail::IMAPClient=HASH(0x7f628587e0e8), "ID (\"name\" \"imapsync\" \"version\" \"2.277\" \"os\" \"linux\" \"vendor\""...) called at ./lib/perl5/Mail/IMAPClient.pm line 1195
        Mail::IMAPClient::tag_and_run(Mail::IMAPClient=HASH(0x7f628587e0e8), "ID (\"name\" \"imapsync\" \"version\" \"2.277\" \"os\" \"linux\" \"vendor\""...) called at ./.venv/bin/imapsync line 6133
        main::imap_id(HASH(0x7f6285a7b5b8), Mail::IMAPClient=HASH(0x7f628587e0e8), "Host1") called at ./.venv/bin/imapsync line 6107
        main::imap_id_stuff(HASH(0x7f6285a7b5b8)) called at ./.venv/bin/imapsync line 2136
        main::single_sync(HASH(0x7f6285a7b5b8), HASH(0x7f628836a6c8), HASH(0x7f6285a87488)) called at ./.venv/bin/imapsync line 1390
ERROR: 4 BAD User is authenticated but not connected. at ./lib/perl5/Mail/IMAPClient.pm line 1298.
        Mail::IMAPClient::_imap_command(Mail::IMAPClient=HASH(0x7f628587e0e8), "ID (\"name\" \"imapsync\" \"version\" \"2.277\" \"os\" \"linux\" \"vendor\""...) called at ./lib/perl5/Mail/IMAPClient.pm line 1195
        Mail::IMAPClient::tag_and_run(Mail::IMAPClient=HASH(0x7f628587e0e8), "ID (\"name\" \"imapsync\" \"version\" \"2.277\" \"os\" \"linux\" \"vendor\""...) called at ./.venv/bin/imapsync line 6133
        main::imap_id(HASH(0x7f6285a7b5b8), Mail::IMAPClient=HASH(0x7f628587e0e8), "Host1") called at ./.venv/bin/imapsync line 6107
        main::imap_id_stuff(HASH(0x7f6285a7b5b8)) called at ./.venv/bin/imapsync line 2136
        main::single_sync(HASH(0x7f6285a7b5b8), HASH(0x7f628836a6c8), HASH(0x7f6285a87488)) called at ./.venv/bin/imapsync line 1390

I can't seem to find IMAP.AccessAsAll in the API permissions listing, since there's no more Exchange in the 'Supported Legacy APIs' List.

Will update once I have progress.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests