code: func (c *Client) grpc() (proto.AuthServiceClient, error) {
  	// it's ok to lock here, because Dial below is not locking
  	c.Lock()
  	defer c.Unlock()
  
  	if c.grpcClient != nil {
  		return c.grpcClient, nil
  	}
  	dialer := grpc.WithDialer(func(addr string, timeout time.Duration) (net.Conn, error) {
  		if c.isClosed() {
  			return nil, trace.ConnectionProblem(nil, "client is closed")
  		}
  		c, err := c.DialContext(context.TODO(), "tcp", addr)
  		if err != nil {
  			log.Debugf("Dial to addr %v failed: %v.", addr, err)
  		}
  		return c, err
  	})
  	tlsConfig := c.TLS.Clone()
  	tlsConfig.NextProtos = []string{http2.NextProtoTLS}
  	log.Debugf("GRPC(): keep alive %v count: %v.", c.KeepAlivePeriod, c.KeepAliveCount)
  	conn, err := grpc.Dial(teleport.APIDomain,
  		dialer,
  		grpc.WithTransportCredentials(credentials.NewTLS(tlsConfig)),
  		grpc.WithKeepaliveParams(keepalive.ClientParameters{
  			Time:    c.KeepAlivePeriod,
  			Timeout: c.KeepAlivePeriod * time.Duration(c.KeepAliveCount),
  		}),
  	)
  	if err != nil {
  		return nil, trail.FromGRPC(err)
  	}
  	c.conn = conn
  	c.grpcClient = proto.NewAuthServiceClient(c.conn)
  
  	return c.grpcClient, nil
  }
docs: // grpc returns grpc client