HTTPS request with client X.509 certificate

In Java to make an HTTPS request with a client certificate, for example to facilitate mTLS authentication for an OAuth client, requires the set up a custom javax.net.ssl.SSLSocketFactory.

Example how to do this in the SDK for mTLS with self_signed_tls_client_auth for the OAuth 2.0 client credentials grant:

import java.net.*;
import java.security.*;
import java.security.cert.*;
import java.util.*;
import javax.net.ssl.*;

import com.nimbusds.jose.jwk.*;
import com.nimbusds.jose.jwk.gen.*;
import com.nimbusds.jwt.util.*;
import com.nimbusds.oauth2.sdk.*;
import com.nimbusds.oauth2.sdk.auth.*;
import com.nimbusds.oauth2.sdk.http.*;
import com.nimbusds.oauth2.sdk.id.*;
import com.nimbusds.oauth2.sdk.token.*;
import com.nimbusds.oauth2.sdk.util.*;

// Generate an RSA public / private key pair and store it securely.
// The public RSA key must be registered with the OAuth 2.0 server
// in the client's metadata
RSAKey rsaJWK = new RSAKeyGenerator(2048)
    .keyIDFromThumbprint(true)
    .generate();

// Generate a self-signed X.509 certificate and sign it with a private key
Date now = new Date();
Date exp = DateUtils.fromSecondsSinceEpoch(now.getTime() + 3600 * 24 * 30);

X509Certificate clientCert = X509CertificateUtils.generateSelfSigned(
    new Issuer(clientInfo.getID()),
    now,
    exp,
    rsaJWK.toRSAPublicKey(),
    rsaJWK.toPrivateKey()
);

// Store the private key together with the certificate
KeyStore ks = KeyStore.getInstance("JKS");
ks.load(null); // init
ks.setKeyEntry("client-auth", rsaJWK.toPrivateKey(), new char[0], new Certificate[]{clientCert});

// Key manager factory for the SSL context
KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
kmf.init(ks, new char[0]);

// Trust manager factory for the SSL context
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null); // null here initialises the TMF with the default trust store.

// Create a new SSL context
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), new SecureRandom());

// Some token request using mTLS self-signed client authentication
TokenRequest tokenRequest = new TokenRequest(
    new URI("https://c2id.com/token"),
    new SelfSignedTLSClientAuthentication(new ClientID("123"), clientCert),
    new ClientCredentialsGrant(),
    new Scope("read", "write")
);

// Make the HTTPS request and set the SSLSocketFactory
httpRequest = tokenRequest.toHTTPRequest();
httpRequest.setSSLSocketFactory(sslContext.getSocketFactory());
httpResponse = httpRequest.send();