Happy Wednesday! Has anyone successfully implement...
# cfml-general
l
Happy Wednesday! Has anyone successfully implemented the solution announced by Mark Takata at https://www.linkedin.com/feed/update/urn:li:activity:7016822066679078913/ in early January to use oAuth for sending e-mail using CFMail? Mark's post (thank you Mark) directs you to a page on the Adobe site at https://helpx.adobe.com/coldfusion/kb/authenticate-imap-pop-smtp-connection-oauth.html that describes the dependencies and code updates that need to be incorporated to make this work. Unfortunately, well after working with Adobe ColdFusion Technical Support for over a month to get this working, I am no closer to getting this working than I was when I first started engaging with them. The first issue I have is when I use the CFOAUTH tag, I receive an access token, and not an authorization token as described on the Adobe page. If I ignore using the CFHTTP call Adobe recommends I use next and just use the access_token value returned by Azure Active Directory as the password for CFMail, my messages get sent successfully. Woo-Hoo! But wait ... not Woo-Hoo. If a different browser is used to attempt to send a message (CFOAUTH is in the flow), the person trying to send the message gets a prompt to authorize my Azure Active Directory app to send mail on behalf of my company. Okay - that makes sense (gulp). Adobe recommended that I just copy and paste the auth_token generated in an Incognito web browsing session into the password attribute for CFMail - that would be good. Well, as you would expect, that works great for an hour, then the access_token value from Azure Active Directory expires and the prompt to a user (could be my customer) would be display to authorize my Azure Active Directory app to send mail for any mailbox in my tenant. Any guidance from anyone who has successfully implemented Adobe's solution for using CFOAuth with CFMail would be greatly appreciated.
t
You need to refresh the jwt, it is another oauth flow if you look at the jwt it will have an expiry time
b
@leonod I've done a couple client projects with oath and azure, but not with cfmail. Just good of fashioned graph api calls
It works pretty well and the json api honestly gives you a lot more control vs cfimap and cfmail. It is a slightly bigger learning curve than cfmail, but if you need a solution today it will work without having to wait for Adobe.
I actually shared my cfimap replacement a while back here in this slack team which shows how to get the access tokens set up.
From your message above, it sounds like you have the wrong oauth flow set up!
You only need to do the browser redirect where the actual end user authorizes the app, etc if you're using that user's permissions and doing like a an SSO sort if thing
But none of that is neccessary just to have your server send mail on behalf of a user. You can create an app with admin permissions that uses a backend flow that's completely invisible to the end user.
That's from the Lucee forum, but there's really nothing specific to Lucee. It's just CFHTTP calls to a REST API.
You can easily add calls to send emails in addition to receiving. Microsoft has pretty thorough docs for their 365 Outlook API.
w
It seems from the OAuth flow, the <cfoauth> tag is not providing the Authorization Code, just the access_token. Without the Auth Code, you could not make further calls to use the refresh token to obtain a new access_token once it expires. Should the <cfoauth> tag provide the Auth Code?
b
I can't help there as I've never used Adobe's built in cfoauth stuff. To be honest, it's always felt a little silly. All you need is a couple HTTP calls, and in some cases, a URL redirect to set up oauth. And either way you have to get all the right IDs set up. I'm not really sure what cfoath is saving you, but certainly seems to limit what you can do.
Just look at my example I posted above. It just takes a single cfhttp call to get the silly auth code. It's not that much code once you get it working.
Now that said, I'm not aware of needing the auth code to refresh your JWT. Usually you just need the refresh token which you should have gotten at the same time as your auth token, but this can be dependent on how you've set up the flow on Azure's side.
In my example I posted above, I'm using the "client credentials" flow so there's really no need to mess with a refresh token. I just grab a new auth token when the old one expires because it's all automated on the backend and the user never sees it.
l
Hi Brad. The CFOAuth call returns the following from Azure Active Directory, which is the access_token and an empty state variable. Thank you for sharing Graph approach above. I will check that out, and I sincerely appreciate your help!
b
Yeah, to be honest I'm not clear which approach cfoauth is taking
Is this a user auth where you redirect a user through a SOO portal, or a client credentials flow where it's al backend?
l
The approach that Adobe provided and that I have been going back and forth with Adobe for a month now to get working has the user authorizing my AAD application to have access to my tenant's mailboxes via a sign-on. Nothing like asking a potential customer to authorize my AAD application to have access to my mailboxes prior to sending me an information request.
b
Yeah, that's sort of a crap flow just to send an E-mail on their behalf
You need to be using a "client credentials" flow
And I have no idea if Adobe is supporting that or not
Part of it is how you set up the app in the Azure portal
This is what I use with my client https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow Scroll down to "*First case: Access token request with a shared secret*". The important bit is
&grant_type=client_credentials
That call immediately returns an access token for your app with whatever permissions you've assigned. This is 100% back end and the user sees nothing. Just a single HTTP call
Here are the permissions I set up in Azure for the app
image.png
Note the mail perms have "admin consent" which means my app can send or receive mail for ANY USER in AD.
This access token is never returned to the browser, of course. It's only used on the server!
Adobe needs to be giving you this flow, but honestly I would forget this cfoauth stuff if it doesn't account for these flows! You just need a single cfhttp call and you'll have a useable access token you can go attack the Graph API with!
I've found the GraphAPI quite easy to use and the JSON format makes it 100 times simpler than the Java classes that power cfimap and cfmail. (I spent a lot of time in Lucee's source code for those tags before moving to the Graph API and wishing I had done so sooner, lol )
@leonod
l
Thanks Brad - I will give this a try and share how it works out. I sincerely appreciate your help!
I do have a question on your AAD permissions. I did not see a Mail.Send permission. Is that covered by the Mail.ReadWrite permission?
b
Just to throw this out-- a few companies have hired Ortus to help consult with them to move their mail processes to oauth or implement SOO with Azure. If this is a big deal, you can have me help do this for you via Ortus consulting. Otherwise, I'm happy to try and guide you here 🙂
Is that covered by the Mail.ReadWrite permission?
Yes, I believe it is. Also note in my screen shot, it says "all mailboxes"
That's a very powerful permission, but it allows one "god mode" app to just directly access any mailbox it wants
l
Thanks Brad - and yes - thank you for sharing that Ortus could help with something like this. I am very close to requesting help from grown-ups in the room like Ortus that has actually implemented this successfully.
👍 2