Email authentication Oauth M365 / Exchange Online

Hi all

Microsoft turns off basic authentication by default for 365 / Exchange Online starting now from the 1st of October 2022:

I couldn’t find a way to authenticate a mailbox with modern authentication (oauth) in ERPNext.

Are there already plans to fix this?
I guess this is affecting many ERPNext users worldwide…

4 Likes

Hi there,

This issue has been flagged in the tracker, but I’m not sure that anyone has sponsored or initiated work on it. ERPNext already supports OAuth in other contexts, but from quick glance at the microsoft docs it’s not quite as simple as just grabbing a token and sending it in place of a password.

I think there are some people interested. We are willing to sponsor it, at least partially.

Anyone else?

1 Like

I’m surprised I didn’t notice this before, but the email account doctype has supported OAuth for gmail since July. I don’t know the first thing about the M365 implementation, but unless there are some major deviations I’d think that porting it over might be relatively straightforward.

1 Like
  • The email/oauth.py has class OAuth it needs to use refresh_token and access_token from “Connected App”/“Token Cache” instead of current custom logic. Class implementation won’t change much, instantiation will need to change to use correct params.
  • EmailAccount.access_token and EmailAccount.refresh_token will be removed and EmailAccount.connected_app link field needs to be added.
  • authorize() button is already part of ConnectedApp

This will make it generic. Google, Microsoft any other using XOAUTH will be able to use this without any code changes. I’m tweaking things locally and trying out if it works.

5 Likes

@revant_one @peterg Please, let me know if any help is needed (testing or anything). I have some M365 accounts in different tenants, and admin access.

Thanks.

Great!
@peterg and @revant_one this might be helpful:
Authenticate an IMAP, POP or SMTP connection using OAuth | Microsoft Learn

@avc we would also be willing to sponsor partially.

Can you guys estimate the hours needed to implement this?

Can anyone help me with this function?

token_cache.get_expires_in() should return remaining seconds.

I am trying this:

	def get_expires_in(self):
		now_utc = datetime.utcnow().replace(tzinfo=pytz.utc)
		expiry_time = frappe.utils.get_datetime(self.modified) + timedelta(seconds=self.expires_in)
		expiry_local = expiry_time.replace(tzinfo=pytz.timezone(frappe.utils.get_time_zone()))
		expiry_utc = expiry_local.astimezone(pytz.utc)
		return (now_utc - expiry_utc).total_seconds()

Any help? I need to get time remaining in seconds on t.get_expires_in() and I need to get True or False on t.is_expired()

EDIT:

this seems to be working

1 Like

No ETA.

3 Likes

Anyone who can setup development bench and has Google / Microsoft Client keys and endpoints can help in testing?

2 Likes

:point_up: Microsoft

Found this thread and figured it was a better place to chat instead of the PR. Are you using user or service principal? Are you able to send email?

Hi:

There are a lot of threads talking about this :slight_smile:
Since some people are working on it, maybe our testing info is useful on PR comments …

Anyway, we can’t get IMAP or POP mail working yet … probably some missconfiguration about scopes, API permissions on tenant, or something like that. I see that your case is different and it is working now. I keep trying!

Thanks!

Is this thing resolved, if yes is there any guide or to follow what should be done?

Hi:

Yes, it is working on latest v14 (14.23.0) and develop branches.

First of all you need to create an app registration on your M365 tenant. Then, configure a connected app on Frappe / Erpnext side.

Here some helpful stuff:

https://frappeframework.com/docs/v14/user/en/guides/app-development/connected-app

Hope this helps.

2 Likes