# mTLS Setup (/sdks/kotlin/how-to/tls/mtls-setup)



## Overview [#overview]

Standard TLS only proves the server's identity — the server itself accepts any client that knows the address and client ID. &#x2A;*Mutual TLS (mTLS)** closes that gap: the client also presents a certificate, so the server verifies who is connecting before accepting the connection. That matters on zero-trust networks and in regulated environments where "reaches the port" isn't an acceptable authorization model — the certificate becomes the credential.

The `tls { }` builder block's `caCertFile`, `certFile`, and `keyFile` (or the `caCertPem` / `certPem` / `keyPem` byte-array variants) wire in three artifacts at client construction: the CA certificate (to verify the server, same as one-way TLS) plus the client's own certificate and private key (for the server to verify in return). Verification happens during the handshake, before any messaging traffic flows.

**Gotchas:** the certificate and key must be a matched pair signed by a CA the server trusts — a mismatch fails the handshake outright; all three inputs must be valid, unexpired PEM, and expiry breaks connections with no warning; and the CA that signed the *client* cert isn't necessarily the CA that verifies the *server* — mixing them up causes "works with TLS, fails with mTLS" confusion.

## Prerequisites [#prerequisites]

* KubeMQ server running with mTLS enabled
* Kotlin SDK installed (`implementation("io.kubemq.sdk:kubemq-sdk-kotlin:1.0.1")`)
* CA certificate, client certificate, and client private key files

## Code [#code]

```kotlin title="MtlsSetupExample.kt"
package io.kubemq.sdk.examples.tls

import io.kubemq.sdk.client.KubeMQClient
import kotlinx.coroutines.runBlocking

private const val ADDRESS = "localhost:50001"
private const val CLIENT_ID = "kotlin-tls-mtls-setup"
private const val CA_CERT_FILE = "/path/to/ca.pem"
private const val CLIENT_CERT_FILE = "/path/to/client.pem"
private const val CLIENT_KEY_FILE = "/path/to/client.key"

fun main() = runBlocking {
    connectWithMutualTls()
    connectWithMutualTlsFromPemBytes()
    println("mTLS setup examples completed.")
}

private fun connectWithMutualTls() {
    println("=== Mutual TLS (mTLS) Connection ===\n")

    // Create a client with mTLS (client cert + key + CA cert)
    try {
        val client = KubeMQClient.queues {
            address = ADDRESS
            clientId = CLIENT_ID
            tls {
                caCertFile = CA_CERT_FILE
                certFile = CLIENT_CERT_FILE
                keyFile = CLIENT_KEY_FILE
            }
        }
        println("mTLS client configured with file paths:")
        println("  CA: $CA_CERT_FILE")
        println("  Cert: $CLIENT_CERT_FILE")
        println("  Key: $CLIENT_KEY_FILE")
        // Uncomment when mTLS server is available:
        // client.use { println("Connected: ${it.ping().host}") }
        client.close()
    } catch (e: Exception) {
        println("mTLS connection failed: ${e.message}")
    }
}

private fun connectWithMutualTlsFromPemBytes() {
    println("\n=== Mutual TLS from PEM bytes ===\n")

    // Load certs from PEM bytes instead of files
    val caBytes = "-----BEGIN CERTIFICATE-----\n... CA cert ...\n-----END CERTIFICATE-----".toByteArray()
    val certBytes = "-----BEGIN CERTIFICATE-----\n... client cert ...\n-----END CERTIFICATE-----".toByteArray()
    val keyBytes = "-----BEGIN PRIVATE KEY-----\n... client key ...\n-----END PRIVATE KEY-----".toByteArray()

    try {
        val client = KubeMQClient.queues {
            address = ADDRESS
            clientId = "$CLIENT_ID-pem"
            tls {
                caCertPem = caBytes
                certPem = certBytes
                keyPem = keyBytes
            }
        }
        println("mTLS client configured with PEM bytes.")
        // Uncomment when mTLS server is available:
        // client.use { println("Connected: ${it.ping().host}") }
        client.close()
    } catch (e: Exception) {
        println("mTLS PEM connection failed: ${e.message}")
    }
}
```

## How It Works [#how-it-works]

* mTLS requires three components: CA certificate, client certificate, and client private key.
* **File-based configuration:** Use `caCertFile`, `certFile`, and `keyFile` with file paths.
* **PEM-bytes configuration:** Use `caCertPem`, `certPem`, and `keyPem` with byte arrays loaded from any source.
* The PEM-bytes approach is useful when certificates come from secrets managers, environment variables, or Kubernetes secrets.
* Both client and server verify each other's certificates for mutual authentication.

## Related [#related]

* [TLS Setup](/sdks/kotlin/how-to/tls/tls-setup)
* [Token Authentication](/sdks/kotlin/how-to/connection/token-auth)
* [Kotlin SDK Reference](/sdks/kotlin/reference/client)
