diff --git a/ca/bootstrap.go b/ca/bootstrap.go
index 7cff35310942edb42080abb337520c4b1788e840..029d13c80a2e5391ce76c37016e7d5e080c43bc0 100644
--- a/ca/bootstrap.go
+++ b/ca/bootstrap.go
@@ -90,6 +90,59 @@ func BootstrapServer(ctx context.Context, token string, base *http.Server) (*htt
 	return base, nil
 }
 
+// BootstrapServerWithMTLS is a helper function that using the given token
+// returns the given http.Server configured with a TLS certificate signed by the
+// Certificate Authority, this server will always require and verify a client
+// certificate. By default the server will kick off a routine that will renew
+// the certificate after 2/3rd of the certificate's lifetime has expired.
+//
+// Usage:
+//   // Default example with certificate rotation.
+//   srv, err := ca.BootstrapServerWithMTLS(context.Background(), token, &http.Server{
+//       Addr: ":443",
+//       Handler: handler,
+//   })
+//
+//   // Example canceling automatic certificate rotation.
+//   ctx, cancel := context.WithCancel(context.Background())
+//   defer cancel()
+//   srv, err := ca.BootstrapServerWithMTLS(ctx, token, &http.Server{
+//       Addr: ":443",
+//       Handler: handler,
+//   })
+//   if err != nil {
+//       return err
+//   }
+//   srv.ListenAndServeTLS("", "")
+func BootstrapServerWithMTLS(ctx context.Context, token string, base *http.Server) (*http.Server, error) {
+	if base.TLSConfig != nil {
+		return nil, errors.New("server TLSConfig is already set")
+	}
+
+	client, err := Bootstrap(token)
+	if err != nil {
+		return nil, err
+	}
+
+	req, pk, err := CreateSignRequest(token)
+	if err != nil {
+		return nil, err
+	}
+
+	sign, err := client.Sign(req)
+	if err != nil {
+		return nil, err
+	}
+
+	tlsConfig, err := client.GetServerMutualTLSConfig(ctx, sign, pk)
+	if err != nil {
+		return nil, err
+	}
+
+	base.TLSConfig = tlsConfig
+	return base, nil
+}
+
 // BootstrapClient is a helper function that using the given bootstrap token
 // return an http.Client configured with a Transport prepared to do TLS
 // connections using the client certificate returned by the certificate
diff --git a/ca/bootstrap_test.go b/ca/bootstrap_test.go
index 3d1863eb22fd2cb5a1d723b1079e4915acb4e165..50a3f1f1f828e5e6828a390c7745fc3805c650da 100644
--- a/ca/bootstrap_test.go
+++ b/ca/bootstrap_test.go
@@ -170,6 +170,52 @@ func TestBootstrapServer(t *testing.T) {
 	}
 }
 
+func TestBootstrapServerWithMTLS(t *testing.T) {
+	srv := startCABootstrapServer()
+	defer srv.Close()
+	token := func() string {
+		return generateBootstrapToken(srv.URL, "subject", "ef742f95dc0d8aa82d3cca4017af6dac3fce84290344159891952d18c53eefe7")
+	}
+	type args struct {
+		ctx   context.Context
+		token string
+		base  *http.Server
+	}
+	tests := []struct {
+		name    string
+		args    args
+		wantErr bool
+	}{
+		{"ok", args{context.Background(), token(), &http.Server{}}, false},
+		{"fail", args{context.Background(), "bad-token", &http.Server{}}, true},
+		{"fail with TLSConfig", args{context.Background(), token(), &http.Server{TLSConfig: &tls.Config{}}}, true},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got, err := BootstrapServerWithMTLS(tt.args.ctx, tt.args.token, tt.args.base)
+			if (err != nil) != tt.wantErr {
+				t.Errorf("BootstrapServerWithMTLS() error = %v, wantErr %v", err, tt.wantErr)
+				return
+			}
+			if tt.wantErr {
+				if got != nil {
+					t.Errorf("BootstrapServerWithMTLS() = %v, want nil", got)
+				}
+			} else {
+				expected := &http.Server{
+					TLSConfig: got.TLSConfig,
+				}
+				if !reflect.DeepEqual(got, expected) {
+					t.Errorf("BootstrapServerWithMTLS() = %v, want %v", got, expected)
+				}
+				if got.TLSConfig == nil || got.TLSConfig.ClientCAs == nil || got.TLSConfig.RootCAs == nil || got.TLSConfig.GetCertificate == nil || got.TLSConfig.GetClientCertificate == nil {
+					t.Errorf("BootstrapServerWithMTLS() invalid TLSConfig = %#v", got.TLSConfig)
+				}
+			}
+		})
+	}
+}
+
 func TestBootstrapClient(t *testing.T) {
 	srv := startCABootstrapServer()
 	defer srv.Close()
diff --git a/ca/tls.go b/ca/tls.go
index d985de2b19451c1ec3ed9d2751740266a237b260..800a6adf7ea7382698ef6a491cd9cc5126afd2f3 100644
--- a/ca/tls.go
+++ b/ca/tls.go
@@ -19,7 +19,7 @@ import (
 
 // GetClientTLSConfig returns a tls.Config for client use configured with the
 // sign certificate, and a new certificate pool with the sign root certificate.
-// The certificate will automatically rotate before expiring.
+// The client certificate will automatically rotate before expiring.
 func (c *Client) GetClientTLSConfig(ctx context.Context, sign *api.SignResponse, pk crypto.PrivateKey) (*tls.Config, error) {
 	cert, err := TLSCertificate(sign, pk)
 	if err != nil {
@@ -32,6 +32,7 @@ func (c *Client) GetClientTLSConfig(ctx context.Context, sign *api.SignResponse,
 
 	tlsConfig := getDefaultTLSConfig(sign)
 	// Note that with GetClientCertificate tlsConfig.Certificates is not used.
+	// Without tlsConfig.Certificates there's not need to use tlsConfig.BuildNameToCertificate()
 	tlsConfig.GetClientCertificate = renewer.GetClientCertificate
 	tlsConfig.PreferServerCipherSuites = true
 	// Build RootCAs with given root certificate
@@ -39,9 +40,6 @@ func (c *Client) GetClientTLSConfig(ctx context.Context, sign *api.SignResponse,
 		tlsConfig.RootCAs = pool
 	}
 
-	// Parse Certificates and build NameToCertificate
-	tlsConfig.BuildNameToCertificate()
-
 	// Update renew function with transport
 	tr, err := getDefaultTransport(tlsConfig)
 	if err != nil {
@@ -56,7 +54,8 @@ func (c *Client) GetClientTLSConfig(ctx context.Context, sign *api.SignResponse,
 
 // GetServerTLSConfig returns a tls.Config for server use configured with the
 // sign certificate, and a new certificate pool with the sign root certificate.
-// The certificate will automatically rotate before expiring.
+// The returned tls.Config will only verify the client certificate if provided.
+// The server certificate will automatically rotate before expiring.
 func (c *Client) GetServerTLSConfig(ctx context.Context, sign *api.SignResponse, pk crypto.PrivateKey) (*tls.Config, error) {
 	cert, err := TLSCertificate(sign, pk)
 	if err != nil {
@@ -70,6 +69,7 @@ func (c *Client) GetServerTLSConfig(ctx context.Context, sign *api.SignResponse,
 	tlsConfig := getDefaultTLSConfig(sign)
 	// Note that GetCertificate will only be called if the client supplies SNI
 	// information or if tlsConfig.Certificates is empty.
+	// Without tlsConfig.Certificates there's not need to use tlsConfig.BuildNameToCertificate()
 	tlsConfig.GetCertificate = renewer.GetCertificate
 	tlsConfig.GetClientCertificate = renewer.GetClientCertificate
 	tlsConfig.PreferServerCipherSuites = true
@@ -93,6 +93,19 @@ func (c *Client) GetServerTLSConfig(ctx context.Context, sign *api.SignResponse,
 	return tlsConfig, nil
 }
 
+// GetServerMutualTLSConfig returns a tls.Config for server use configured with
+// the sign certificate, and a new certificate pool with the sign root certificate.
+// The returned tls.Config will always require and verify a client certificate.
+// The server certificate will automatically rotate before expiring.
+func (c *Client) GetServerMutualTLSConfig(ctx context.Context, sign *api.SignResponse, pk crypto.PrivateKey) (*tls.Config, error) {
+	tlsConfig, err := c.GetServerTLSConfig(ctx, sign, pk)
+	if err != nil {
+		return nil, err
+	}
+	tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
+	return tlsConfig, nil
+}
+
 // Transport returns an http.Transport configured to use the client certificate from the sign response.
 func (c *Client) Transport(ctx context.Context, sign *api.SignResponse, pk crypto.PrivateKey) (*http.Transport, error) {
 	tlsConfig, err := c.GetClientTLSConfig(ctx, sign, pk)
diff --git a/ca/tls_test.go b/ca/tls_test.go
index 9c61d6deab3c7d0ee984d5f147843f2580bdb82b..182310c4ddbeb8ca235669dbb96ced78afe9825a 100644
--- a/ca/tls_test.go
+++ b/ca/tls_test.go
@@ -111,6 +111,127 @@ func TestClient_GetServerTLSConfig_http(t *testing.T) {
 		t.Fatalf("Client.GetServerTLSConfig() error = %v", err)
 	}
 	clientDomain := "test.domain"
+	// Create server with given tls.Config
+	srv := startTestServer(tlsConfig, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+		if req.RequestURI != "/no-cert" {
+			if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
+				w.Write([]byte("fail"))
+				t.Error("http.Request.TLS does not have peer certificates")
+				return
+			}
+			if req.TLS.PeerCertificates[0].Subject.CommonName != clientDomain {
+				w.Write([]byte("fail"))
+				t.Errorf("http.Request.TLS.PeerCertificates[0].Subject.CommonName = %s, wants %s", req.TLS.PeerCertificates[0].Subject.CommonName, clientDomain)
+				return
+			}
+			if !reflect.DeepEqual(req.TLS.PeerCertificates[0].DNSNames, []string{clientDomain}) {
+				w.Write([]byte("fail"))
+				t.Errorf("http.Request.TLS.PeerCertificates[0].DNSNames %v, wants %v", req.TLS.PeerCertificates[0].DNSNames, []string{clientDomain})
+				return
+			}
+		}
+		w.Write([]byte("ok"))
+	}))
+	defer srv.Close()
+
+	tests := []struct {
+		name      string
+		path      string
+		wantErr   bool
+		getClient func(*testing.T, *Client, *api.SignResponse, crypto.PrivateKey) *http.Client
+	}{
+		{"with transport", "", false, func(t *testing.T, client *Client, sr *api.SignResponse, pk crypto.PrivateKey) *http.Client {
+			tr, err := client.Transport(context.Background(), sr, pk)
+			if err != nil {
+				t.Errorf("Client.Transport() error = %v", err)
+				return nil
+			}
+			return &http.Client{
+				Transport: tr,
+			}
+		}},
+		{"with tlsConfig", "", false, func(t *testing.T, client *Client, sr *api.SignResponse, pk crypto.PrivateKey) *http.Client {
+			tlsConfig, err := client.GetClientTLSConfig(context.Background(), sr, pk)
+			if err != nil {
+				t.Errorf("Client.GetClientTLSConfig() error = %v", err)
+				return nil
+			}
+			tr, err := getDefaultTransport(tlsConfig)
+			if err != nil {
+				t.Errorf("getDefaultTransport() error = %v", err)
+				return nil
+			}
+			return &http.Client{
+				Transport: tr,
+			}
+		}},
+		{"ok with no cert", "/no-cert", false, func(t *testing.T, client *Client, sr *api.SignResponse, pk crypto.PrivateKey) *http.Client {
+			root, err := RootCertificate(sr)
+			if err != nil {
+				t.Errorf("RootCertificate() error = %v", err)
+				return nil
+			}
+			tlsConfig := getDefaultTLSConfig(sr)
+			tlsConfig.RootCAs = x509.NewCertPool()
+			tlsConfig.RootCAs.AddCert(root)
+
+			tr, err := getDefaultTransport(tlsConfig)
+			if err != nil {
+				t.Errorf("getDefaultTransport() error = %v", err)
+				return nil
+			}
+			return &http.Client{
+				Transport: tr,
+			}
+		}},
+		{"fail with default", "/no-cert", true, func(t *testing.T, client *Client, sr *api.SignResponse, pk crypto.PrivateKey) *http.Client {
+			return &http.Client{}
+		}},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			client, sr, pk := sign(clientDomain)
+			cli := tt.getClient(t, client, sr, pk)
+			if cli != nil {
+				resp, err := cli.Get(srv.URL + tt.path)
+				if (err != nil) != tt.wantErr {
+					t.Errorf("http.Client.Get() error = %v, wantErr %v", err, tt.wantErr)
+					return
+				}
+				if tt.wantErr {
+					return
+				}
+				defer resp.Body.Close()
+				b, err := ioutil.ReadAll(resp.Body)
+				if err != nil {
+					t.Fatalf("ioutil.RealAdd() error = %v", err)
+				}
+				if !bytes.Equal(b, []byte("ok")) {
+					t.Errorf("response body unexpected, got %s, want ok", b)
+				}
+			}
+		})
+	}
+}
+
+func TestClient_GetServerTLSConfig_renew(t *testing.T) {
+	if testing.Short() {
+		t.Skip("skipping test in short mode.")
+	}
+
+	// Start CA
+	ca := startCATestServer()
+	defer ca.Close()
+
+	client, sr, pk := signDuration(ca, "127.0.0.1", 1*time.Minute)
+	tlsConfig, err := client.GetServerTLSConfig(context.Background(), sr, pk)
+	if err != nil {
+		t.Fatalf("Client.GetServerTLSConfig() error = %v", err)
+	}
+	clientDomain := "test.domain"
+	fingerprints := make(map[string]struct{})
+
 	// Create server with given tls.Config
 	srv := startTestServer(tlsConfig, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
 		if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
@@ -128,15 +249,125 @@ func TestClient_GetServerTLSConfig_http(t *testing.T) {
 			t.Errorf("http.Request.TLS.PeerCertificates[0].DNSNames %v, wants %v", req.TLS.PeerCertificates[0].DNSNames, []string{clientDomain})
 			return
 		}
+		// Add serial number to check rotation
+		sum := sha256.Sum256(req.TLS.PeerCertificates[0].Raw)
+		fingerprints[hex.EncodeToString(sum[:])] = struct{}{}
+		w.Write([]byte("ok"))
+	}))
+	defer srv.Close()
+
+	// Clients: transport and tlsConfig
+	client, sr, pk = signDuration(ca, clientDomain, 1*time.Minute)
+	tr1, err := client.Transport(context.Background(), sr, pk)
+	if err != nil {
+		t.Fatalf("Client.Transport() error = %v", err)
+	}
+	client, sr, pk = signDuration(ca, clientDomain, 1*time.Minute)
+	tlsConfig, err = client.GetClientTLSConfig(context.Background(), sr, pk)
+	if err != nil {
+		t.Fatalf("Client.GetClientTLSConfig() error = %v", err)
+	}
+	tr2, err := getDefaultTransport(tlsConfig)
+	if err != nil {
+		t.Fatalf("getDefaultTransport() error = %v", err)
+	}
+
+	// Disable keep alives to force TLS handshake
+	tr1.DisableKeepAlives = true
+	tr2.DisableKeepAlives = true
+
+	tests := []struct {
+		name   string
+		client *http.Client
+	}{
+		{"with transport", &http.Client{Transport: tr1}},
+		{"with tlsConfig", &http.Client{Transport: tr2}},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			resp, err := tt.client.Get(srv.URL)
+			if err != nil {
+				t.Fatalf("http.Client.Get() error = %v", err)
+			}
+			defer resp.Body.Close()
+			b, err := ioutil.ReadAll(resp.Body)
+			if err != nil {
+				t.Fatalf("ioutil.RealAdd() error = %v", err)
+			}
+			if !bytes.Equal(b, []byte("ok")) {
+				t.Errorf("response body unexpected, got %s, want ok", b)
+			}
+		})
+	}
+
+	if l := len(fingerprints); l != 2 {
+		t.Errorf("number of fingerprints unexpected, got %d, want 4", l)
+	}
+
+	// Wait for renewal 40s == 1m-1m/3
+	log.Printf("Sleeping for %s ...\n", 40*time.Second)
+	time.Sleep(40 * time.Second)
+
+	for _, tt := range tests {
+		t.Run("renewed "+tt.name, func(t *testing.T) {
+			resp, err := tt.client.Get(srv.URL)
+			if err != nil {
+				t.Fatalf("http.Client.Get() error = %v", err)
+			}
+			defer resp.Body.Close()
+			b, err := ioutil.ReadAll(resp.Body)
+			if err != nil {
+				t.Fatalf("ioutil.RealAdd() error = %v", err)
+			}
+			if !bytes.Equal(b, []byte("ok")) {
+				t.Errorf("response body unexpected, got %s, want ok", b)
+			}
+		})
+	}
+
+	if l := len(fingerprints); l != 4 {
+		t.Errorf("number of fingerprints unexpected, got %d, want 4", l)
+	}
+}
+
+func TestClient_GetServerMutualTLSConfig_http(t *testing.T) {
+	client, sr, pk := sign("127.0.0.1")
+	tlsConfig, err := client.GetServerMutualTLSConfig(context.Background(), sr, pk)
+	if err != nil {
+		t.Fatalf("Client.GetServerTLSConfig() error = %v", err)
+	}
+	clientDomain := "test.domain"
+	// Create server with given tls.Config
+	srv := startTestServer(tlsConfig, http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
+		if req.RequestURI != "/no-cert" {
+			if req.TLS == nil || len(req.TLS.PeerCertificates) == 0 {
+				w.Write([]byte("fail"))
+				t.Error("http.Request.TLS does not have peer certificates")
+				return
+			}
+			if req.TLS.PeerCertificates[0].Subject.CommonName != clientDomain {
+				w.Write([]byte("fail"))
+				t.Errorf("http.Request.TLS.PeerCertificates[0].Subject.CommonName = %s, wants %s", req.TLS.PeerCertificates[0].Subject.CommonName, clientDomain)
+				return
+			}
+			if !reflect.DeepEqual(req.TLS.PeerCertificates[0].DNSNames, []string{clientDomain}) {
+				w.Write([]byte("fail"))
+				t.Errorf("http.Request.TLS.PeerCertificates[0].DNSNames %v, wants %v", req.TLS.PeerCertificates[0].DNSNames, []string{clientDomain})
+				return
+			}
+		}
 		w.Write([]byte("ok"))
 	}))
 	defer srv.Close()
 
 	tests := []struct {
 		name      string
+		path      string
+		wantErr   bool
 		getClient func(*testing.T, *Client, *api.SignResponse, crypto.PrivateKey) *http.Client
 	}{
-		{"with transport", func(t *testing.T, client *Client, sr *api.SignResponse, pk crypto.PrivateKey) *http.Client {
+		{"with transport", "", false, func(t *testing.T, client *Client, sr *api.SignResponse, pk crypto.PrivateKey) *http.Client {
 			tr, err := client.Transport(context.Background(), sr, pk)
 			if err != nil {
 				t.Errorf("Client.Transport() error = %v", err)
@@ -146,7 +377,7 @@ func TestClient_GetServerTLSConfig_http(t *testing.T) {
 				Transport: tr,
 			}
 		}},
-		{"with tlsConfig", func(t *testing.T, client *Client, sr *api.SignResponse, pk crypto.PrivateKey) *http.Client {
+		{"with tlsConfig", "", false, func(t *testing.T, client *Client, sr *api.SignResponse, pk crypto.PrivateKey) *http.Client {
 			tlsConfig, err := client.GetClientTLSConfig(context.Background(), sr, pk)
 			if err != nil {
 				t.Errorf("Client.GetClientTLSConfig() error = %v", err)
@@ -161,6 +392,25 @@ func TestClient_GetServerTLSConfig_http(t *testing.T) {
 				Transport: tr,
 			}
 		}},
+		{"fail with no cert", "/no-cert", true, func(t *testing.T, client *Client, sr *api.SignResponse, pk crypto.PrivateKey) *http.Client {
+			root, err := RootCertificate(sr)
+			if err != nil {
+				t.Errorf("RootCertificate() error = %v", err)
+				return nil
+			}
+			tlsConfig := getDefaultTLSConfig(sr)
+			tlsConfig.RootCAs = x509.NewCertPool()
+			tlsConfig.RootCAs.AddCert(root)
+
+			tr, err := getDefaultTransport(tlsConfig)
+			if err != nil {
+				t.Errorf("getDefaultTransport() error = %v", err)
+				return nil
+			}
+			return &http.Client{
+				Transport: tr,
+			}
+		}},
 	}
 
 	for _, tt := range tests {
@@ -168,9 +418,13 @@ func TestClient_GetServerTLSConfig_http(t *testing.T) {
 			client, sr, pk := sign(clientDomain)
 			cli := tt.getClient(t, client, sr, pk)
 			if cli != nil {
-				resp, err := cli.Get(srv.URL)
-				if err != nil {
-					t.Fatalf("http.Client.Get() error = %v", err)
+				resp, err := cli.Get(srv.URL + tt.path)
+				if (err != nil) != tt.wantErr {
+					t.Errorf("http.Client.Get() error = %v, wantErr %v", err, tt.wantErr)
+					return
+				}
+				if tt.wantErr {
+					return
 				}
 				defer resp.Body.Close()
 				b, err := ioutil.ReadAll(resp.Body)
@@ -185,7 +439,7 @@ func TestClient_GetServerTLSConfig_http(t *testing.T) {
 	}
 }
 
-func TestClient_GetServerTLSConfig_renew(t *testing.T) {
+func TestClient_GetServerMutualTLSConfig_renew(t *testing.T) {
 	if testing.Short() {
 		t.Skip("skipping test in short mode.")
 	}
@@ -195,7 +449,7 @@ func TestClient_GetServerTLSConfig_renew(t *testing.T) {
 	defer ca.Close()
 
 	client, sr, pk := signDuration(ca, "127.0.0.1", 1*time.Minute)
-	tlsConfig, err := client.GetServerTLSConfig(context.Background(), sr, pk)
+	tlsConfig, err := client.GetServerMutualTLSConfig(context.Background(), sr, pk)
 	if err != nil {
 		t.Fatalf("Client.GetServerTLSConfig() error = %v", err)
 	}
diff --git a/examples/README.md b/examples/README.md
index cfffbc262bab0c6778a6459afb6266bf5bfdcfd2..64b099ccada127236aee3a48154678a7792ea5ea 100644
--- a/examples/README.md
+++ b/examples/README.md
@@ -142,7 +142,8 @@ password `password` hardcoded, but you can create your own using `step ca init`.
 
 These examples show the use of other helper methods, they are simple ways to
 create TLS configured http.Server and http.Client objects. The methods are
-`BootstrapServer` and `BootstrapClient` and they are used like:
+`BootstrapServer`, `BootstrapServerWithMTLS` and `BootstrapClient` and they are
+used like:
 
 ```go
 // Get a cancelable context to stop the renewal goroutines and timers.
@@ -159,6 +160,21 @@ if err != nil {
 srv.ListenAndServeTLS("", "")
 ```
 
+```go
+// Get a cancelable context to stop the renewal goroutines and timers.
+ctx, cancel := context.WithCancel(context.Background())
+defer cancel()
+// Create an http.Server that requires a client certificate
+srv, err := ca.BootstrapServerWithMTLS(ctx, token, &http.Server{
+    Addr: ":8443",
+    Handler: handler,
+})
+if err != nil {
+    panic(err)
+}
+srv.ListenAndServeTLS("", "")
+```
+
 ```go
 // Get a cancelable context to stop the renewal goroutines and timers.
 ctx, cancel := context.WithCancel(context.Background())
@@ -171,6 +187,9 @@ if err != nil {
 resp, err := client.Get("https://localhost:8443")
 ```
 
+We will demonstrate the mTLS configuration if a different example, for this one
+we will only verify it if provided.
+
 To run the example first we will start the certificate authority:
 ```sh
 certificates $ bin/step-ca examples/pki/config/ca.json
@@ -229,6 +248,47 @@ Server responded: Hello Mike at 2018-11-03 01:52:54.682787 +0000 UTC!!!
 ...
 ```
 
+## Bootstrap mTLS Client & Server
+
+This example demonstrates a stricter configuration of the bootstrap server, this
+one always requires a valid client certificate.
+
+As always, to run this example will require the Certificate Authority running:
+```sh
+certificates $ bin/step-ca examples/pki/config/ca.json
+2018/11/02 18:29:25 Serving HTTPS on :9000 ...
+```
+
+We will start the mTLS server and we will type `password` when step asks for the
+provisioner password:
+```sh
+certificates $ export STEPPATH=examples/pki
+certificates $ export STEP_CA_URL=https://localhost:9000
+certificates $ go run examples/bootstrap-mtls-server/server.go $(step ca token localhost)
+✔ Key ID: DmAtZt2EhmZr_iTJJ387fr4Md2NbzMXGdXQNW1UWPXk (mariano@smallstep.com)
+Please enter the password to decrypt the provisioner key:
+Listening on :8443 ...
+```
+
+For mTLS, curl and curl with the root certificate will fail:
+```sh
+certificates $ curl --cacert examples/pki/secrets/root_ca.crt https://localhost:8443
+curl: (35) error:1401E412:SSL routines:CONNECT_CR_FINISHED:sslv3 alert bad certificate
+```
+
+But if we the client with the certificate name Mike we'll see:
+```sh
+certificates $ export STEPPATH=examples/pki
+certificates $ export STEP_CA_URL=https://localhost:9000
+certificates $ go run examples/bootstrap-client/client.go $(step ca token Mike)
+✔ Key ID: DmAtZt2EhmZr_iTJJ387fr4Md2NbzMXGdXQNW1UWPXk (mariano@smallstep.com)
+Please enter the password to decrypt the provisioner key:
+Server responded: Hello Mike at 2018-11-07 21:54:00.140022 +0000 UTC!!!
+Server responded: Hello Mike at 2018-11-07 21:54:01.140827 +0000 UTC!!!
+Server responded: Hello Mike at 2018-11-07 21:54:02.141578 +0000 UTC!!!
+...
+```
+
 ## Certificate rotation
 
 We can use the bootstrap-server to demonstrate the certificate rotation. We've
@@ -240,7 +300,7 @@ rotates after approximately two thirds of the duration has passed.
 ```sh
 certificates $ export STEPPATH=examples/pki
 certificates $ export STEP_CA_URL=https://localhost:9000
-certificates $ go run examples/bootstrap-server/server.go $(step ca token localhost))
+certificates $ go run examples/bootstrap-server/server.go $(step ca token localhost)
 ✔ Key ID: YYNxZ0rq0WsT2MlqLCWvgme3jszkmt99KjoGEJJwAKs (mike@smallstep.com)
 Please enter the password to decrypt the provisioner key:
 Listening on :8443 ...
diff --git a/examples/bootstrap-mtls-server/server.go b/examples/bootstrap-mtls-server/server.go
new file mode 100644
index 0000000000000000000000000000000000000000..3527c368c678c891a589a9163fb27874e8d12238
--- /dev/null
+++ b/examples/bootstrap-mtls-server/server.go
@@ -0,0 +1,43 @@
+package main
+
+import (
+	"context"
+	"fmt"
+	"net/http"
+	"os"
+	"time"
+
+	"github.com/smallstep/certificates/ca"
+)
+
+func main() {
+	if len(os.Args) != 2 {
+		fmt.Fprintf(os.Stderr, "Usage: %s <token>\n", os.Args[0])
+		os.Exit(1)
+	}
+
+	token := os.Args[1]
+
+	// make sure to cancel the renew goroutine
+	ctx, cancel := context.WithCancel(context.Background())
+	defer cancel()
+
+	srv, err := ca.BootstrapServerWithMTLS(ctx, token, &http.Server{
+		Addr: ":8443",
+		Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+			name := "nobody"
+			if r.TLS != nil && len(r.TLS.PeerCertificates) > 0 {
+				name = r.TLS.PeerCertificates[0].Subject.CommonName
+			}
+			w.Write([]byte(fmt.Sprintf("Hello %s at %s!!!", name, time.Now().UTC())))
+		}),
+	})
+	if err != nil {
+		panic(err)
+	}
+
+	fmt.Println("Listening on :8443 ...")
+	if err := srv.ListenAndServeTLS("", ""); err != nil {
+		panic(err)
+	}
+}