Configure HTTPS for Jersey Client in Java Applications
Secure communication is essential when integrating Java applications with external APIs over HTTPS. The Jersey Client API provides a convenient way to send HTTP requests, but additional configuration is required when dealing with SSL certificates and mutual TLS (mTLS). This article will explore how to configure Jersey Client for HTTPS.
1. Creating Keystores and Certificates
Before making HTTPS calls, it is common to work with keystores and certificates. A keystore holds private keys and their corresponding certificates, while a truststore holds public certificates of trusted entities. For local testing, we’ll create a CA, sign server and client certs with it, then build PKCS#12 keystores and a truststore.
# Make a working folder mkdir -p keystore # Generate a private key for the CA openssl genrsa -out ca-key.pem 2048 # Generate a self-signed root certificate for the CA openssl req -x509 -new -nodes -key ca-key.pem -sha256 -days 3650 \ -out ca-cert.pem \ -subj "/C=US/ST=CA/L=SanFrancisco/O=ExampleCA/OU=Dev/CN=ExampleRootCA" # Generate a private key for the server openssl genrsa -out server-key.pem 2048 # Generate a certificate signing request (CSR) for the server openssl req -new -key server-key.pem -out server.csr \ -subj "/C=US/ST=CA/L=SanFrancisco/O=ExampleServer/OU=Dev/CN=localhost" # Sign the server CSR with the CA certificate openssl x509 -req -in server.csr -CA ca-cert.pem -CAkey ca-key.pem \ -CAcreateserial -out server-cert.pem -days 365 -sha256 # Generate a private key for the client openssl genrsa -out client-key.pem 2048 # Generate a certificate signing request (CSR) for the client openssl req -new -key client-key.pem -out client.csr \ -subj "/C=US/ST=CA/L=SanFrancisco/O=ExampleClient/OU=Dev/CN=client" # Sign the client CSR with the CA certificate openssl x509 -req -in client.csr -CA ca-cert.pem -CAkey ca-key.pem \ -CAcreateserial -out client-cert.pem -days 365 -sha256 # Package Server Certificate and Key into PKCS12 Keystore openssl pkcs12 -export \ -in server-cert.pem \ -inkey server-key.pem \ -certfile ca-cert.pem \ -out server-keystore.p12 \ -name server \ -password pass:password # Package Client Certificate and Key into PKCS12 Keystore openssl pkcs12 -export \ -in client-cert.pem \ -inkey client-key.pem \ -certfile ca-cert.pem \ -out client-keystore.p12 \ -name client \ -password pass:password # Create a Truststore and Import the CA Certificate keytool -importcert \ -file ca-cert.pem \ -keystore truststore.p12 \ -storetype PKCS12 \ -alias myca \ -storepass password \ -noprompt
The server keystore is used by our HTTPS server, the client keystore is used by the client for mTLS, and the truststore tells the client which CAs it trusts (so it can trust our server’s certificate).
2. Maven Dependencies
We first need to set up our pom.xml with Jersey Client and Apache HttpComponents for SSL utilities.
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>3.1.9</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>3.1.9</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.2.1</version>
</dependency>
</dependencies>
3. Building an SSLContext with Certificates
Now we create a utility class that loads our truststore and keystore into an SSLContext.
public class HttpsClientFactory {
private static final String CERTS_DIR = "keystore";
private static final String PASSWORD = "password";
public static SSLContext createSslContext() throws Exception {
char[] password = PASSWORD.toCharArray();
return SSLContextBuilder.create()
.loadTrustMaterial(
Paths.get(CERTS_DIR, "truststore.p12").toFile(),
password)
.loadKeyMaterial(
Paths.get(CERTS_DIR, "client-keystore.p12").toFile(),
password,
password)
.build();
}
}
This utility method builds an SSLContext by loading the truststore (truststore.p12) and client keystore (client-keystore.p12). With this setup, the client can authenticate the server and present its own certificate for mutual TLS.
3.1 Using Jersey Client with HTTPS
With the SSLContext ready, let’s build and run a Jersey Client that connects to a secure server.
public class HttpsClientApp {
public static void main(String[] args) throws Exception {
// Create SSLContext using our keystore and truststore
var sslContext = HttpsClientFactory.createSslContext();
// Build Jersey Client
Client client = ClientBuilder.newBuilder()
.sslContext(sslContext)
.build();
// Make HTTPS request to secured API
Response response = client
.target("https://localhost:8443/secure-api/hello")
.request()
.get();
System.out.println("Status: " + response.getStatus());
System.out.println("Response: " + response.readEntity(String.class));
response.close();
client.close();
}
}
This example creates a Jersey Client with the custom SSLContext and performs a GET request against https://localhost:8443/secure-api/hello. If the server is correctly configured with HTTPS and trusts our CA, the request will succeed.
Configuring a Spring Boot Server with HTTPS and Mutual TLS
To test the Jersey Client, we need a server that supports HTTPS and mutual TLS. Spring Boot makes this easy. We just configure it with our generated server keystore (server-keystore.p12) and truststore (truststore.p12).
First, we add a very simple REST controller that the Jersey client will call.
@SpringBootApplication
public class HttpsServerApplication {
public static void main(String[] args) {
SpringApplication.run(HttpsServerApplication.class, args);
}
}
@RestController
class SecureController {
@GetMapping("/secure-api/hello")
public String hello() {
return "Hello, Secure World!";
}
}
This creates a Spring Boot app exposing /secure-api/hello.
Configuring HTTPS and Mutual TLS
Now we tell Spring Boot to use the server keystore and truststore we generated earlier (server-keystore.p12 and truststore.p12). Add this to src/main/resources/application.yml:
server:
port: 8443
ssl:
enabled: true
key-store: classpath:keystore/server-keystore.p12
key-store-password: password
key-store-type: PKCS12
trust-store: classpath:keystore/truststore.p12
trust-store-password: password
trust-store-type: PKCS12
client-auth: need # require client certificate for mutual TLS
Here:
key-store– the server’s own certificate (server-keystore.p12)trust-store– used to validate client certificates (truststore.p12)client-auth: need– enforces mutual TLS, rejecting clients without valid certs
You can start the server using the command mvn spring-boot:run. Once it is running, the application will be accessible at https://localhost:8443/secure-api/hello, and it will only accept requests from clients that present a valid client certificate (client-keystore.p12).
Testing End-to-End
Now run the Jersey Client project we built earlier. You should see output like:
Status: 200 Response: Hello, Secure World!
4. Using JVM Parameters for Truststore
Another way to configure SSL is by setting JVM system properties. This approach is simpler when we want all HTTPS connections in the application to use the same truststore, without manually configuring each client. We can set these properties either from the command line or inside our Java code.
Setting JVM Properties in Java Code
We can also set these properties programmatically in our main class:
public class TruststoreExample {
private static final String CERTS_DIR = "src/main/resources/keystore";
private static final String PASSWORD = "password";
public static void main(String[] args) {
// Configure JVM parameters
System.setProperty("javax.net.ssl.trustStore", CERTS_DIR + "/truststore.p12");
System.setProperty("javax.net.ssl.trustStorePassword", PASSWORD);
System.setProperty("javax.net.ssl.keyStore", CERTS_DIR + "/client-keystore.p12");
System.setProperty("javax.net.ssl.keyStorePassword", PASSWORD);
// Create a Jersey client
Client client = ClientBuilder.newClient();
// Send HTTPS GET request
Response response = client
.target("https://localhost:8443/secure-api/hello")
.request()
.get();
if (response.getStatus() == 200) {
System.out.println("Request successful: " + response.readEntity(String.class));
} else {
System.err.println("Failed with HTTP error code: " + response.getStatus());
}
response.close();
client.close();
}
}
Here we configure the truststore and keystore globally by setting system properties. Any HTTPS connection initiated by this JVM will automatically use these certificates. This removes the need to manually build an SSLContext in every client, which is convenient for applications where all HTTPS connections should use the same SSL configuration.
5. Conclusion
In this article, we explored multiple ways of using HTTPS with Jersey Client in Java. We started by generating keystores and truststores, configured Jersey Client with a custom SSLContext, and finally demonstrated how to configure SSL globally with JVM system properties. The system property approach is best when we want to apply SSL settings across the entire JVM, while the programmatic SSLContext method provides more fine-grained control per client.
6. Download the Source Code
This article explored how to use the Jersey Client with HTTPS in Java.
You can download the full source code of this example here: Java https jersey client

