How to Authenticate Exchange Server(On-Premise) with CBA using java8

Gourav Kumar 60 Reputation points
2025-10-09T08:01:34.2+00:00

Hi everyone,

We are currently migrating from Exchange Online to Exchange On-Prem and want to implement pure Certificate-Based Authentication (CBA). Following the official Microsoft documentation (https://learn.microsoft.com/en-us/exchange/plan-and-deploy/post-installation-tasks/configure-certificate-based-auth), we were able to get CBA working for Outlook on the web (OWA) and ActiveSync.

However, in our Java application, we use IMAP and SMTP (via javax.mail) to read and send emails, which worked fine previously with Basic or OAuth authentication in Exchange Online.

We have the following questions:

  1. Is pure CBA supported for IMAP and SMTP in Exchange On-Prem?

If yes, can anyone provide a POC in Java showing how to authenticate using a client certificate with IMAP/SMTP?

If not, are there any alternative approaches to achieve certificate-based authentication in Java for Exchange On-Prem?

For context:

We attempted using the External SASL mechanism in IMAP, but it seems not supported.

We are using the standard JavaMail dependency to create sessions and send/receive emails.

Any guidance, examples, or workarounds would be highly appreciated, as this is blocking our migration efforts.

Thank you!Hi everyone,

We are currently migrating from Exchange Online to Exchange On-Prem and want to implement pure Certificate-Based Authentication (CBA). Following the official Microsoft documentation (link), we were able to get CBA working for Outlook on the web (OWA) and ActiveSync.

However, in our Java application, we use IMAP and SMTP (via javax.mail) to read and send emails, which worked fine previously with Basic or OAuth authentication in Exchange Online.

We have the following questions:

Is pure CBA supported for IMAP and SMTP in Exchange On-Prem?

If yes, can anyone provide a POC in Java showing how to authenticate using a client certificate with IMAP/SMTP?

If not, are there any alternative approaches to achieve certificate-based authentication in Java for Exchange On-Prem?

For context:

  • We attempted to use the External SASL mechanism in IMAP, but it seems not supported.

We are using the standard JavaMail dependency to create sessions and send/receive emails.

Any guidance, examples, or workarounds would be highly appreciated, as this is blocking our efforts.

Thank you!

Exchange | Exchange Server | Management
Exchange | Exchange Server | Management

The administration and maintenance of Microsoft Exchange Server to ensure secure, reliable, and efficient email and collaboration services across an organization.

0 comments No comments

Answer accepted by question author
Francisco Montilla 30,710 Reputation points Independent Advisor
2025-10-09T11:01:49.0433333+00:00

Hi Gourav,

Exchange Server on-prem does not support authenticating IMAP or SMTP clients with a user’s client certificate.

Certificate-based auth in Exchange is implemented on IIS virtual directories such as OWA, ECP and ActiveSync, and you can extend the same IIS client-certificate mapping to EWS. IMAP and POP run as Windows services, not in IIS, and SMTP client submission is handled by the Front End receive connector. None of those endpoints accept a user client certificate for per-mailbox authentication. Microsoft's CBA guidance is limited to IIS vdirs, and Microsoft’s on-prem modern auth matrix shows IMAP and POP are not supported there either. For SMTP, certificates are used for server-to-server mutual TLS on receive connectors, not for authenticating end-users sending mail.

What works well on Exchange on-prem for a Java app that must be pure CBA is to use EWS over HTTPS, enable client-certificate mapping on the EWS virtual directory in IIS, and then call EWS SOAP from Java while presenting the user's client cert. Microsoft's docs show how to turn on CBA at the IIS layer, and although the article walks through OWA and ActiveSync, the same IIS setting applies to EWS.

If you must keep IMAP and SMTP in this Java app, Exchange on-prem can only authenticate IMAP with user credentials using login or integrated mechanisms, and SMTP client submission on port 587 requires user authentication with TLS. Certificates there are for transport security and server-to-server trust, not for user sign-in.

P.S.: I wrote a small PoC, but it is being filtered so I cannot post it. I'm sorry.

I hope this helps clarifying!

Was this answer helpful?

0 comments No comments

Answer accepted by question author
Francisco Montilla 30,710 Reputation points Independent Advisor
2025-10-09T10:59:21.5366667+00:00

Hi Gourav,

Exchange Server on-prem does not support authenticating IMAP or SMTP clients with a user’s client certificate.

Certificate-based auth in Exchange is implemented on IIS virtual directories such as OWA, ECP and ActiveSync, and you can extend the same IIS client-certificate mapping to EWS. IMAP and POP run as Windows services, not in IIS, and SMTP client submission is handled by the Front End receive connector. None of those endpoints accept a user client certificate for per-mailbox authentication. Microsoft's CBA guidance is limited to IIS vdirs, and Microsoft’s on-prem modern auth matrix shows IMAP and POP are not supported there either. For SMTP, certificates are used for server-to-server mutual TLS on receive connectors, not for authenticating end-users sending mail.

What works well on Exchange on-prem for a Java app that must be pure CBA is to use EWS over HTTPS, enable client-certificate mapping on the EWS virtual directory in IIS, and then call EWS SOAP from Java while presenting the user’s client cert. Microsoft's docs show how to turn on CBA at the IIS layer, and although the article walks through OWA and ActiveSync, the same IIS setting applies to EWS.

Here is a minimal Java 8 PoC that loads a user's client certificate from a PKCS#12 file, builds an HTTPS connection to EWS, and runs a simple FindItem request against the Inbox. On the server side you must have EWS reachable at https://mail.example.com/EWS/Exchange.asmx, require client certificates on the EWS vdir, and map the client cert to the correct AD user (UPN mapping works well). On the client side replace file paths, passwords and URLs as appropriate.

import javax.net.ssl.*;
import java.io.*;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.cert.CertificateException;

public class EwsCbaPoC {

    // Call this once at startup to enable mutual TLS using the user's client cert.
    static void configureClientCert(String pfxPath, String pfxPassword,
                                    String truststorePath, String truststorePassword)
            throws KeyStoreException, IOException, NoSuchAlgorithmException,
                   CertificateException, UnrecoverableKeyException, KeyManagementException {

        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        try (FileInputStream fis = new FileInputStream(pfxPath)) {
            keyStore.load(fis, pfxPassword.toCharArray());
        }
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(keyStore, pfxPassword.toCharArray());

        TrustManagerFactory tmf;
        if (truststorePath != null) {
            KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); // JKS by default
            try (FileInputStream fis = new FileInputStream(truststorePath)) {
                trustStore.load(fis, truststorePassword.toCharArray());
            }
            tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(trustStore);
        } else {
            tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init((KeyStore) null); // use default JVM trust
        }

        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());
        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
        HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> hostname.equalsIgnoreCase("mail.example.com"));
    }

    static String callEws(String url, String soapAction, String bodyXml) throws IOException {
        byte[] payload = bodyXml.getBytes(StandardCharsets.UTF_8);
        HttpsURLConnection conn = (HttpsURLConnection) new URL(url).openConnection();
        conn.setConnectTimeout(15000);
        conn.setReadTimeout(30000);
        conn.setRequestMethod("POST");
        conn.setDoOutput(true);
        conn.setRequestProperty("Content-Type", "text/xml; charset=UTF-8");
        conn.setRequestProperty("SOAPAction", soapAction);
        try (OutputStream os = conn.getOutputStream()) {
            os.write(payload);
        }
        int code = conn.getResponseCode();
        InputStream is = (code >= 200 && code < 300) ? conn.getInputStream() : conn.getErrorStream();
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        byte[] buf = new byte[8192];
        int r;
        while ((r = is.read(buf)) != -1) baos.write(buf, 0, r);
        String resp = new String(baos.toByteArray(), StandardCharsets.UTF_8);
        if (code < 200 || code >= 300) throw new IOException("HTTP " + code + ": " + resp);
        return resp;
    }

    public static void main(String[] args) throws Exception {
        configureClientCert("C:/certs/user.pfx", "pfxPassword",
                            null, null); // or supply a corporate truststore

        String ewsUrl = "https://mail.example.com/EWS/Exchange.asmx";

        String findItemBody =
            "<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" " +
            "xmlns:t=\"http://schemas.microsoft.com/exchange/services/2006/types\">" +
            "<soap:Header>" +
            "<t:RequestServerVersion Version=\"Exchange2013\"/>" +
            "</soap:Header>" +
            "<soap:Body>" +
            "<FindItem xmlns=\"http://schemas.microsoft.com/exchange/services/2006/messages\" Traversal=\"Shallow\">" +
            "<ItemShape><t:BaseShape>IdOnly</t:BaseShape>" +
            "<t:AdditionalProperties>" +
            "<t:FieldURI FieldURI=\"item:Subject\"/>" +
            "<t:FieldURI FieldURI=\"item:DateTimeReceived\"/>" +
            "<t:FieldURI FieldURI=\"item:From\"/>" +
            "</t:AdditionalProperties></ItemShape>" +
            "<ParentFolderIds><t:DistinguishedFolderId Id=\"inbox\"/></ParentFolderIds>" +
            "<MaxEntriesReturned>10</MaxEntriesReturned>" +
            "</FindItem>" +
            "</soap:Body></soap:Envelope>";

        String response = callEws(ewsUrl,
                "http://schemas.microsoft.com/exchange/services/2006/messages/FindItem",
                findItemBody);

        System.out.println(response);
    }
}

To send mail without SMTP, post a CreateItem SOAP with MessageDisposition set to SendAndSaveCopy and provide a Message with ToRecipients and a Body. That works entirely over HTTPS with the user's client certificate mapped to their AD identity, so no passwords and no OAuth are involved. Microsoft's EWS authentication article covers the protocol side, while the CBA article covers the IIS side.

If you must keep IMAP and SMTP in this Java app, Exchange on-prem can only authenticate IMAP with user credentials using login or integrated mechanisms, and SMTP client submission on port 587 requires user authentication with TLS. Certificates there are for transport security and server-to-server trust, not for user sign-in.

I hope this helps clarifying!

Was this answer helpful?


1 additional answer

Sort by: Most helpful
  1. Deleted

    This answer has been deleted due to a violation of our Code of Conduct. The answer was manually reported or identified through automated detection before action was taken. Please refer to our Code of Conduct for more information.


    Comments have been turned off. Learn more

Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.