The site from which I am scraping requires a client side SSL certificate, which is very easy to deal with using the Requests library for Python, simply by passing the path of the certificate to the constructor of a session. But the documentation for Play gives a somewhat unclear explanation on how to achieve this, by saying that you first need direct access to the underlying AsyncHttpClient instance and customizing it:
WS does not support client certificates (aka mutual TLS / MTLS / client authentication). You should set the SSLContext directly in an instance of AsyncHttpClientConfig and set up the appropriate KeyStore and TrustStore.
The problem is, there does not seem to be a way to pass a customized AsyncHttpClientConfig to the client, since the passing of the config is hidden inside private methods (see here if you are interested).
After reading lots of confusing documentation on Java and SSL (practically none exists for Scala), it turns out the solution is not specific to either Scala or Play Framework. The JVM will handle your certificates for you, and the AsyncHttpClient used by Play just uses the ones that the JVM knows about. So your code does not need to specify the certificate, instead you can import it into a keystore and pass the path to the keystore to the JVM using command line arguments. Here is how I did it.
First, you need the client certificate, its private key, and the CA certificate of the authority that signed your certificate. I will call them example.crt, example.key, and cacert.crt. Mine were in PEM format, but they must be converted to PKCS12. The openssl command can do this for you.
openssl pkcs12 -export -in example.crt -inkey example.key -out certs.p12 -name client -CAfile cacert.crt -caname rootWhile the command is running, you will be asked to provide a password to protect the output file. The output file is called certs.p12, which you can use to create a JVM keystore using the keytool command that is included with the JDK.
keytool -importkeystore -deststorepass p@ssw0rd -destkeypass p@ssw0rd -destkeystore keystore.jks -srckeystore certs.p12 -srcstoretype PKCS12 -srcstorepass p@ssw0rd -alias clientThe -srcstorepass argument needs to be the password that you provided when converting your certificate to PKCS12 format. Now you will have a keystore file called keystore.jks. When you fire up your JVM, pass to it the path of your new keystore and its password.
java [args ...] -Djavax.net.ssl.keyStore=/path/to/keystore.jks -Djavax.net.ssl.keyStorePassword=p@ssw0rdNow your Play WS client will automagically use the client certificate from the keystore. For security purposes, you probably don't really want to pass a command line argument containing the password of your keystore, so you may set the properties in your code by reading the password from a properly protected file or some other source. Also, don't actually use 'p@ssw0rd' for your password! But this should be enough to illustrate what is required to get it working.