title: How to get client certificates in Go HTTPS server
body: <p>I'm trying to understand how to get client's certificates in Go web server. Here is a server code:</p>
  
  <pre><code>package main
  
  import (
      "log"
      "net/http"
      "net/http/httputil"
  )
  
  func defaultHandler(w http.ResponseWriter, r *http.Request) {
      dump, err := httputil.DumpRequest(r, true)
      log.Println("HTTP request", r, string(dump), err)
      log.Println("HTTP TLS", r.TLS, string(r.TLS.TLSUnique))
      certs := r.TLS.PeerCertificates
      log.Println("HTTP CERTS", certs)
      w.WriteHeader(http.StatusMethodNotAllowed)
      w.Write([]byte("Hello"))
  }
  
  func main() {
      http.HandleFunc("/", defaultHandler)
      http.ListenAndServeTLS(":8080", "server.crt", "server.key", nil)
  }
  </code></pre>
  
  <p>and here is client code</p>
  
  <pre><code>package main
  
  import (
      "crypto/tls"
      "io/ioutil"
      "log"
      "net/http"
      "os"
  )
  
  func HttpClient() (client *http.Client) {
      uckey := os.Getenv("X509_USER_KEY")
      ucert := os.Getenv("X509_USER_CERT")
      x509cert, err := tls.LoadX509KeyPair(ucert, uckey)
      if err != nil {
          panic(err.Error())
      }
      certs := []tls.Certificate{x509cert}
      if len(certs) == 0 {
         client = &amp;http.Client{}
         return
      }
      tr := &amp;http.Transport{
          TLSClientConfig: &amp;tls.Config{Certificates: certs,
          InsecureSkipVerify: true},
      }
      client = &amp;http.Client{Transport: tr}
      return
  }
  
  func main() {
      rurl := "https://localhost:8080"
      client := HttpClient()
      req, err := http.NewRequest("GET", rurl, nil)
      if err != nil {
         log.Println("Unable to make GET request", err)
         os.Exit(1)
      }
      req.Header.Add("Accept", "*/*")
      resp, err := client.Do(req)
      if err != nil {
          log.Println(err)
          os.Exit(1)
      }
      defer resp.Body.Close()
      data, err := ioutil.ReadAll(resp.Body)
      log.Println(string(data))
  }
  </code></pre>
  
  <p>If I run both server and a client I see the following on a server side:</p>
  
  <pre><code>2017/02/08 15:46:49 HTTP request &amp;{GET / HTTP/1.1 1 1 map[User-Agent:[Go-http-client/1.1] Accept:[*/*] Accept-Encoding:[gzip]] {} 0 [] false localhost:8080 map[] map[] &lt;nil&gt; map[] 127.0.0.1:58941 / 0xc4204ef080 &lt;nil&gt; &lt;nil&gt; 0xc420014d40} GET / HTTP/1.1
  Host: localhost:8080
  Accept: */*
  Accept-Encoding: gzip
  User-Agent: Go-http-client/1.1
  
   &lt;nil&gt;
  2017/02/08 15:46:49 HTTP TLS &amp;{771 true false 49195  true localhost [] [] []   [] [203 144 196 105 155 216 89 105 83 90 93 4]} ːiSZ]
  2017/02/08 15:46:49 HTTP CERTS []
  </code></pre>
  
  <p>As you can see the client's certificates are empty.</p>
  
  <p>While if I invoke curl call to a server providing my certificates, then I can see server certificates:</p>
  
  <pre><code>curl -L -k --key mykey.key --cert mycert.pem -vvv https://localhost:8080
  *   Trying 127.0.0.1...
  * TCP_NODELAY set
  * Connected to localhost (127.0.0.1) port 8080 (#0)
  * ALPN, offering http/1.1
  * Cipher selection: ALL:!EXPORT:!EXPORT40:!EXPORT56:!aNULL:!LOW:!RC4:@STRENGTH
  * successfully set certificate verify locations:
  *   CAfile: /opt/local/share/curl/curl-ca-bundle.crt
      CApath: none
  * TLSv1.2 (OUT), TLS header, Certificate Status (22):
  * TLSv1.2 (OUT), TLS handshake, Client hello (1):
  * TLSv1.2 (IN), TLS handshake, Server hello (2):
  * TLSv1.2 (IN), TLS handshake, Certificate (11):
  * TLSv1.2 (IN), TLS handshake, Server key exchange (12):
  * TLSv1.2 (IN), TLS handshake, Server finished (14):
  * TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
  * TLSv1.2 (OUT), TLS change cipher, Client hello (1):
  * TLSv1.2 (OUT), TLS handshake, Finished (20):
  * TLSv1.2 (IN), TLS change cipher, Client hello (1):
  * TLSv1.2 (IN), TLS handshake, Finished (20):
  * SSL connection using TLSv1.2 / ECDHE-ECDSA-AES128-GCM-SHA256
  * ALPN, server accepted to use http/1.1
  * Server certificate:
  *  subject: C=US; ST=NY; L=Town; O=Bla-Bla
  *  start date: Feb  8 14:12:06 2017 GMT
  *  expire date: Feb  6 14:12:06 2027 GMT
  *  issuer: C=US; ST=NY; L=Ithaca; O=Cornell
  *  SSL certificate verify result: self signed certificate (18), continuing anyway.
  &gt; GET / HTTP/1.1
  &gt; Host: localhost:8080
  &gt; User-Agent: curl/7.52.1
  &gt; Accept: */*
  </code></pre>
  
  <p>As you can see SSL negotiation is in place and curl client successfully reports server certificate. What I need is to access client's certificate on a <strong>server side</strong> to do proper authentication. But so far I can't see any client's certificate.</p>
  
  <p>Any help is really welcome.
  Thanks,
  Valentin.</p>