In the last couple of months, Microsoft has been gradually deprecating and disabling basic authentication for Microsoft Exchange Online protocols like POP and IMAP. The last opportunity to switch to the new, modern, OAuth 2.0-based authentication is by end of December 2022.
Welcome to Part 2 of this series. Part 1 covered the Azure setup and testing. Now we are going to showcase how to configure Flowable and Spring Boot and finally how to use plain Spring and javax.mail to access a mailbox over IMAP. Missed Part 1? Read it here.
Flowable products use the Spring Security OAuth2 Client library to configure OAuth2 authentication to 3rd-party servers.
We are starting with the Spring Security OAuth2 Client configuration. The following listing shows properties to obtain access tokens for Microsoft Office 365 Exchange Online, using the client credentials flow:
spring.security.oauth2.client.provider.exchange-server-imap.issuer-uri=https://login.microsoftonline.com/<tenantId>/v2.0
spring.security.oauth2.client.registration.exchange-server-imap.client-id=<application_client_id>
spring.security.oauth2.client.registration.exchange-server-imap.client-secret=<client_secret>
spring.security.oauth2.client.registration.exchange-server-imap.scope=https://outlook.office365.com/.default
spring.security.oauth2.client.registration.exchange-server-imap.authorization-grant-type=client_credentials
The exchange-server-imap is the client registration id. It is a custom name and can be named as desired. Multiple providers and registrations are possible to authenticate against multiple OAuth2 endpoints. You can find the Endpoints of the issuer-uri, alongside all the other available Endpoints for a registered app in Microsoft Azure here:
With the upcoming Flowable Enterprise v3.13 and v3.12.5 it is possible to obtain access tokens wherever expressions are supported. The expression expects a serviceId, which maps to the client registration id above:
${flwAuthTokenUtils.getAccessToken('exchange-server-imap')}
Flowables EMail inbound channel with Office 365 OAuth2
The following example showcases this new expression util. It is used to configure an EMail Inbound channel and uses this new functionality in the password field of the IMAP configuration. Please also note the required custom imaps.* properties are required to successfully connect to Microsoft Office 365 Exchange Online with this authentication method:
NOTE: The expression used in the "password" field is a SpEl Expression, therefore it starts with #{ and not with ${. Adjust the interval and the other properties to your needs. Those are just used as an example here. You might want to read your messages as read, etc.
The default implementation takes care of caching the token and only requesting a new one, when the token is expired. Also, token expiration is being taken care of (see the chapter below for details).
IDLE for Office 365 Exchange Online
IDLE is the alternative for polling mode in IMAP. Instead of polling for messages, IDLE mode pushes to the application in case a new Email arrives in the mailbox. This sounds good at the first glance; however, it turns out to be more error-prone in practice, with different problems from vendor to vendor. Additionally, not all SMTP providers support IDLE. Office 365 supports IDLE in general, however, the community reported some problems in the past regarding the stability of this feature: MS Techcommunity article regarding imap idle.
Long story short: Polling with a reasonable interval seems to be the more stable solution for now. In any case: Start with polling, get the functionality done and try out if IDLE works for your use case, if you would like to rely on it.
Troubleshoot? Enable debug properties
Add mail.debug debug properties to the "Custom properties" section, to get details printed to the console:
For a full example of how easy it is to receive and handle EMails with Flowable and how to model some process or case logic around it, see the how-to guide on receiving and handling EMails with Flowable from Valentin Zickner. Also check our helpful how-to video guides on YouTube for tons of different topics on what Flowable is capable of.
Filip Hrisafov used the EMail inbound channel in his Flowfest'22 session "Event-based sharding for hyper-scaling", which is available on YouTube. Watch it, as long as it still is hot.
This section discusses an example of how to use Spring Security OAuth2 Client API and javax.mail API to connect to an Exchange Online mailbox. This example is independent of Flowable APIs. We are happy to share to our knowledge in this regard. Remember? Our open source thinking.
NOTE: Access tokens do expire. Expiration needs to be handled in the application code. This approach shown below, using an Authenticator, takes care of that by taking advantage of the javax.mail connection pool: It removes the not-authenticated connection (when the token expires) from the pool and creates a new authenticated one.
BEWARE: You might need to adapt your existing code creating the javax.mail.Session, in case the password is passed as static string. It will work first in tests, but FAIL with authentication errors when the token expires!
First, let's create a @Service capable of returning an access token for a username and clientRegistrationId:
@Service
class OAuth2TokenService {
AuthorizedClientServiceOAuth2AuthorizedClientManager clients;
OAuth2TokenService(ClientRegistrationRepository repo, OAuth2AuthorizedClientService service) {
this.clients = new AuthorizedClientServiceOAuth2AuthorizedClientManager(repo, service);
}
String fetchAccessToken(String username, String clientRegistrationId) {
OAuth2AuthorizeRequest authorizeRequest = OAuth2AuthorizeRequest
.withClientRegistrationId(clientRegistrationId)
.principal(username)
.build();
OAuth2AuthorizedClient authorizedClient = clients.authorize(authorizeRequest);
return authorizedClient.getAccessToken().getTokenValue();
}
}
Next, we use this service in a special TokenAuthenticator extending Authenticator to fetch and use the access token as password:
class TokenAuthenticator extends javax.mail.Authenticator {
String username; String serviceId; OAuth2TokenService tokenService;
// Constructor omitted
@Override
protected PasswordAuthentication getPasswordAuthentication() {
String accessToken = tokenService.fetchAccessToken(username, serviceId);
return new PasswordAuthentication(username, accessToken);
}
}
Finally the TokenAuthenticator is used, when creating the javax.mail Session:
String email = "mymail@acme.com";
Properties props = new Properties();
props.put("mail.store.protocol", "imaps");
props.put("mail.imaps.host", "outlook.office365.com");
props.put("mail.imaps.port", "993");
props.put("mail.imaps.ssl.enable", "true");
props.put("mail.imaps.starttls.enable", "true");
props.put("mail.imaps.auth", "true");
props.put("mail.imaps.auth.mechanisms", "XOAUTH2");
props.put("mail.imaps.user", email);
props.put("mail.imaps.auth.plain.disable", "true");
props.put("mail.imaps.auth.xoauth2.disable", "false");
// Dependecy-Injected OAuth2TokenService
Authenticator authenticator = new TokenAuthenticator(email, "exchange-server-imap", this.oauth2TokenService);
// Important to use authenticator here, for token based auth
Session session = Session.getInstance(props, authenticator);
session.setDebug(true); Store store = session.getStore("imaps");
store.connect();
Folder folder = store.getFolder("Inbox");
folder.open(Folder.READ_ONLY);
System.out.printf("Nr of messages in mailbox: %d", folder.getMessageCount());
Note the usage of the Authenticator, instead of hard-coding username / token.
Part 2 of this limited series on using modern OAuth2-based authentication to access Microsoft Office 365 Exchange Online mailboxes showcased
How to configure Flowables Mail inbound channel using the new expression util method ${flwAuthTokenUtils.getAccessToken('oauth-server')} to fetch access tokens and how to use it in the mail inbound channel configuration instead of a literal passsword.
How to correctly use javax.mail APIs to using the authentication mechanism to not run into authentication errors due to expired tokens.
Part 1 covered the Azure setup.
I hope you found some valuable insights in this series. Feel free to share the articles if you found them useful.
Enterprises need to process a large volume if documents daily — quickly and accurately. Flowable uses Intelligent Document Processing (IDP) to improve content processing and support enterprises in managing documents end-to-end.
CMMN was mainly designed with case management in mind to handle dynamic, human-driven processes, where the execution is not always a straight line, but might involve human decision to drive the process forward. But it can do way more than that.
Tools like ChatGPT can handle a variety of business tasks, automating nearly everything. And it’s true, GenAI really can do a wide range of tasks that humans do currently. Why not let business users work directly with AI then? And what about Agentic AI?