diff --git a/Makefile b/Makefile
index d80d7b27289c99f5689c687bcb6c8c137b921b11..3fa12fdd4f286874431c8dd2a4d691556a956cea 100644
--- a/Makefile
+++ b/Makefile
@@ -312,7 +312,7 @@ E = @echo
 Q = @
 endif
 
-VERSION = 0.11.0.0
+VERSION = 0.12.0.0
 
 CPPFLAGS_NO_ARCH += $(addprefix -I, $(INCLUDES)) $(addprefix -D, $(DEFINES))
 CPPFLAGS += $(CPPFLAGS_NO_ARCH) $(ARCH_FLAGS)
diff --git a/binding.gyp b/binding.gyp
index 502b9d7a73c7099f942db3a322b242367a2dc5f9..1883f730fc80b67f9d8795eccd09ab997a1c8419 100644
--- a/binding.gyp
+++ b/binding.gyp
@@ -347,11 +347,12 @@
         "src/node/ext/node_grpc.cc",
         "src/node/ext/server.cc",
         "src/node/ext/server_credentials.cc",
-        "src/node/ext/timeval.cc"
+        "src/node/ext/timeval.cc",
       ],
       "dependencies": [
-        "grpc"
+        "grpc",
+        "gpr",
       ]
-    }
+    },
   ]
 }
diff --git a/build.yaml b/build.yaml
index bd93a16bcb37d77b2ef5c406dec506a7dd9b5cac..c40a6bb7b46f3b1758cf92972d2ae44f6db6c22b 100644
--- a/build.yaml
+++ b/build.yaml
@@ -5,7 +5,7 @@ settings:
   '#': The public version number of the library.
   version:
     major: 0
-    minor: 11
+    minor: 12
     micro: 0
     build: 0
 filegroups:
@@ -2224,3 +2224,19 @@ vspackages:
   props: false
   redist: false
   version: 1.7.0.1
+node_modules:
+- deps:
+  - grpc
+  - gpr
+  name: grpc_node
+  src:
+  - src/node/ext/byte_buffer.cc
+  - src/node/ext/call.cc
+  - src/node/ext/call_credentials.cc
+  - src/node/ext/channel.cc
+  - src/node/ext/channel_credentials.cc
+  - src/node/ext/completion_queue_async_worker.cc
+  - src/node/ext/node_grpc.cc
+  - src/node/ext/server.cc
+  - src/node/ext/server_credentials.cc
+  - src/node/ext/timeval.cc
diff --git a/doc/PROTOCOL-HTTP2.md b/doc/PROTOCOL-HTTP2.md
index 7f7055bb4df7b35391a7f25761ab1c28bfe6708f..7a26724c85ded4b28214845a5e5a3e84a882ab3f 100644
--- a/doc/PROTOCOL-HTTP2.md
+++ b/doc/PROTOCOL-HTTP2.md
@@ -44,8 +44,9 @@ Request-Headers are delivered as HTTP2 headers in HEADERS + CONTINUATION frames.
 * **Message-Type** → "grpc-message-type" {_type name for message schema_}
 * **Custom-Metadata** → Binary-Header / ASCII-Header
 * **Binary-Header** → {Header-Name "-bin" } {_base64 encoded value_}
-* **ASCII-Header** → Header-Name {_value_}
+* **ASCII-Header** → Header-Name ASCII-Value
 * **Header-Name** → 1\*( %x30-39 / %x61-7A / "\_" / "-") ; 0-9 a-z \_ -
+* **ASCII-Value** → 1\*( %x20-%x7E ) ; space and printable ASCII
 
 
 HTTP2 requires that reserved headers, ones starting with ":" appear before all other headers. Additionally implementations should send **Timeout** immediately after the reserved headers and they should send the **Call-Definition** headers before sending **Custom-Metadata**.
@@ -56,6 +57,23 @@ If **Timeout** is omitted a server should assume an infinite timeout. Client imp
 
 Note that HTTP2 does not allow arbitrary octet sequences for header values so binary header values must be encoded using Base64 as per https://tools.ietf.org/html/rfc4648#section-4. Implementations MUST accept padded and un-padded values and should emit un-padded values. Applications define binary headers by having their names end with "-bin". Runtime libraries use this suffix to detect binary headers and properly apply base64 encoding & decoding as headers are sent and received.
 
+**Custom-Metadata** header order is not guaranteed to be preserved except for
+values with duplicate header names. Duplicate header names may have their values
+joined with "," as the delimiter and be considered semantically equivalent.
+Implementations must split **Binary-Header**s on "," before decoding the
+Base64-encoded values.
+
+**ASCII-Value** should not have leading or trailing whitespace. If it contains
+leading or trailing whitespace, it may be stripped. The **ASCII-Value**
+character range defined is more strict than HTTP. Implementations must not error
+due to receiving an invalid **ASCII-Value** that's a valid **field-value** in
+HTTP, but the precise behavior is not strictly defined: they may throw the value
+away or accept the value. If accepted, care must be taken to make sure that the
+application is permitted to echo the value back as metadata. For example, if the
+metadata is provided to the application as a list in a request, the application
+should not trigger an error by providing that same list as the metadata in the
+response.
+
 Servers may limit the size of **Request-Headers**, with a default of 8 KiB
 suggested.  Implementations are encouraged to compute total header size like
 HTTP/2's `SETTINGS_MAX_HEADER_LIST_SIZE`: the sum of all header fields, for each
diff --git a/doc/grpc-auth-support.md b/doc/grpc-auth-support.md
index 800fbedd80c63307d58aaba759731b06a96515cd..b210ff15333a4ee0c68e5ee35e8d72cc045fcf1e 100644
--- a/doc/grpc-auth-support.md
+++ b/doc/grpc-auth-support.md
@@ -36,9 +36,9 @@ authenticate the server and encrypt all data.
 ```cpp
 SslCredentialsOptions ssl_opts;  // Options to override SSL params, empty by default
 // Create the credentials object by providing service account key in constructor
-std::unique_ptr<Credentials> creds = CredentialsFactory::SslCredentials(ssl_opts);
+std::shared_ptr<ChannelCredentials> creds = SslCredentials(ssl_opts);
 // Create a channel using the credentials created in the previous step
-std::shared_ptr<ChannelInterface> channel = CreateChannel(server_name, creds, channel_args);
+std::shared_ptr<Channel> channel = CreateChannel(server_name, creds);
 // Create a stub on the channel
 std::unique_ptr<Greeter::Stub> stub(Greeter::NewStub(channel));
 // Make actual RPC calls on the stub.
@@ -55,9 +55,9 @@ passed to the factory method.
 gRPC applications can use a simple API to create a credential that works in various deployment scenarios.
 
 ```cpp
-std::unique_ptr<Credentials> creds = CredentialsFactory::GoogleDefaultCredentials();
+std::shared_ptr<ChannelCredentials> creds = GoogleDefaultCredentials();
 // Create a channel, stub and make RPC calls (same as in the previous example)
-std::shared_ptr<ChannelInterface> channel = CreateChannel(server_name, creds, channel_args);
+std::shared_ptr<Channel> channel = CreateChannel(server_name, creds);
 std::unique_ptr<Greeter::Stub> stub(Greeter::NewStub(channel));
 grpc::Status s = stub->sayHello(&context, *request, response);
 ```
diff --git a/doc/interop-test-descriptions.md b/doc/interop-test-descriptions.md
index 8649213bc6ad4c6d3b957b3f70441555f3ec1943..53cc47b1f8379677f0ed89811915f03b2983cd77 100644
--- a/doc/interop-test-descriptions.md
+++ b/doc/interop-test-descriptions.md
@@ -4,7 +4,7 @@ Interoperability Test Case Descriptions
 Client and server use
 [test.proto](https://github.com/grpc/grpc/blob/master/test/proto/test.proto)
 and the [gRPC over HTTP/2 v2
-protocol](doc/PROTOCOL-HTTP2.md).
+protocol](https://github.com/grpc/grpc/blob/master/doc/PROTOCOL-HTTP2.md).
 
 Client
 ------
diff --git a/examples/cpp/cpptutorial.md b/examples/cpp/cpptutorial.md
index 78de014f97d1978b4195dca5b84306fc66a8375c..cd1cddb11157be6f1bd48d07955a15f5bd4898a0 100644
--- a/examples/cpp/cpptutorial.md
+++ b/examples/cpp/cpptutorial.md
@@ -245,7 +245,7 @@ To call service methods, we first need to create a *stub*.
 First we need to create a gRPC *channel* for our stub, specifying the server address and port we want to connect to without SSL:
 
 ```cpp
-grpc::CreateChannel("localhost:50051", grpc::InsecureCredentials());
+grpc::CreateChannel("localhost:50051", grpc::InsecureChannelCredentials());
 ```
 
 Now we can use the channel to create our stub using the `NewStub` method provided in the `RouteGuide` class we generated from our .proto.
diff --git a/examples/cpp/helloworld/README.md b/examples/cpp/helloworld/README.md
index b16c084583dc97abad2fa1a4ffae0991f1531d96..7a7194d11186a6134aff2c494d9f9f2854dead4b 100644
--- a/examples/cpp/helloworld/README.md
+++ b/examples/cpp/helloworld/README.md
@@ -94,7 +94,7 @@ $ protoc -I ../../protos/ --cpp_out=. ../../protos/helloworld.proto
   arguments as follows
 
     ```
-    auto channel = CreateChannel("localhost:50051", InsecureCredentials());
+    auto channel = CreateChannel("localhost:50051", InsecureChannelCredentials());
     ```
 
 - Create a stub. A stub implements the rpc methods of a service and in the
diff --git a/examples/cpp/helloworld/greeter_async_client.cc b/examples/cpp/helloworld/greeter_async_client.cc
index 923c8ffa743dba81cbe8740492ace7a2772b6e96..35014267febe9ccd1bab506de49e38ccf18af987 100644
--- a/examples/cpp/helloworld/greeter_async_client.cc
+++ b/examples/cpp/helloworld/greeter_async_client.cc
@@ -114,9 +114,9 @@ int main(int argc, char** argv) {
   // Instantiate the client. It requires a channel, out of which the actual RPCs
   // are created. This channel models a connection to an endpoint (in this case,
   // localhost at port 50051). We indicate that the channel isn't authenticated
-  // (use of InsecureCredentials()).
-  GreeterClient greeter(
-      grpc::CreateChannel("localhost:50051", grpc::InsecureCredentials()));
+  // (use of InsecureChannelCredentials()).
+  GreeterClient greeter(grpc::CreateChannel(
+      "localhost:50051", grpc::InsecureChannelCredentials()));
   std::string user("world");
   std::string reply = greeter.SayHello(user);  // The actual RPC call!
   std::cout << "Greeter received: " << reply << std::endl;
diff --git a/examples/cpp/helloworld/greeter_client.cc b/examples/cpp/helloworld/greeter_client.cc
index 6cd8353a9fb21498d04d5a6bff1a0b9ce40a10d9..bf3b63cb5774752914d28e4662973db549c11466 100644
--- a/examples/cpp/helloworld/greeter_client.cc
+++ b/examples/cpp/helloworld/greeter_client.cc
@@ -84,9 +84,9 @@ int main(int argc, char** argv) {
   // Instantiate the client. It requires a channel, out of which the actual RPCs
   // are created. This channel models a connection to an endpoint (in this case,
   // localhost at port 50051). We indicate that the channel isn't authenticated
-  // (use of InsecureCredentials()).
-  GreeterClient greeter(
-      grpc::CreateChannel("localhost:50051", grpc::InsecureCredentials()));
+  // (use of InsecureChannelCredentials()).
+  GreeterClient greeter(grpc::CreateChannel(
+      "localhost:50051", grpc::InsecureChannelCredentials()));
   std::string user("world");
   std::string reply = greeter.SayHello(user);
   std::cout << "Greeter received: " << reply << std::endl;
diff --git a/examples/cpp/route_guide/route_guide_client.cc b/examples/cpp/route_guide/route_guide_client.cc
index 85173a393256832369a2ad701eed2e50c80b0a52..b9abe72a5bd7a8d453f1405d50f3b9426a16717e 100644
--- a/examples/cpp/route_guide/route_guide_client.cc
+++ b/examples/cpp/route_guide/route_guide_client.cc
@@ -234,7 +234,8 @@ int main(int argc, char** argv) {
   // Expect only arg: --db_path=path/to/route_guide_db.json.
   std::string db = routeguide::GetDbFileContent(argc, argv);
   RouteGuideClient guide(
-      grpc::CreateChannel("localhost:50051", grpc::InsecureCredentials()),
+      grpc::CreateChannel("localhost:50051",
+                          grpc::InsecureChannelCredentials()),
       db);
 
   std::cout << "-------------- GetFeature --------------" << std::endl;
diff --git a/examples/node/README.md b/examples/node/README.md
index df681e85dd7ed0f6a094ed75fdf8d6d18ba0f794..09c56f7fa6f402cce6e1df6205ecdd1c17ebedee 100644
--- a/examples/node/README.md
+++ b/examples/node/README.md
@@ -4,7 +4,7 @@ gRPC in 3 minutes (Node.js)
 PREREQUISITES
 -------------
 
-- `node`: This requires Node 10.x or greater.
+- `node`: This requires Node 0.10.x or greater.
 - [homebrew][] on Mac OS X.  This simplifies the installation of the gRPC C core.
 
 INSTALL
diff --git a/examples/python/helloworld/greeter_server.py b/examples/python/helloworld/greeter_server.py
index 1514d8f270bef2eca2e1aac16a367172b73daf35..2cde5add435d6ebd204637a2217c98a89e87c00d 100644
--- a/examples/python/helloworld/greeter_server.py
+++ b/examples/python/helloworld/greeter_server.py
@@ -50,7 +50,7 @@ def serve():
     while True:
       time.sleep(_ONE_DAY_IN_SECONDS)
   except KeyboardInterrupt:
-    server.stop()
+    server.stop(0)
 
 if __name__ == '__main__':
   serve()
diff --git a/include/grpc++/channel.h b/include/grpc++/channel.h
index 60c816d58ac942a210cbb5291002afea7744e7b3..d6d72a9cf981fb3178a6dc2090ce30d1d093fea2 100644
--- a/include/grpc++/channel.h
+++ b/include/grpc++/channel.h
@@ -47,8 +47,8 @@ namespace grpc {
 class CallOpSetInterface;
 class ChannelArguments;
 class CompletionQueue;
-class Credentials;
-class SecureCredentials;
+class ChannelCredentials;
+class SecureChannelCredentials;
 
 template <class R>
 class ClientReader;
diff --git a/include/grpc++/client_context.h b/include/grpc++/client_context.h
index 7046f939e5e57298434c9d5fb9eeb8dd83eae307..5c6f432c9a70bd0ae220bc27bd4cb70a3fd921b2 100644
--- a/include/grpc++/client_context.h
+++ b/include/grpc++/client_context.h
@@ -53,15 +53,16 @@
 #include <memory>
 #include <string>
 
-#include <grpc/compression.h>
-#include <grpc/grpc.h>
-#include <grpc/support/log.h>
-#include <grpc/support/time.h>
+#include <grpc++/impl/sync.h>
 #include <grpc++/security/auth_context.h>
 #include <grpc++/support/config.h>
 #include <grpc++/support/status.h>
 #include <grpc++/support/string_ref.h>
 #include <grpc++/support/time.h>
+#include <grpc/compression.h>
+#include <grpc/grpc.h>
+#include <grpc/support/log.h>
+#include <grpc/support/time.h>
 
 struct census_context;
 
@@ -69,7 +70,7 @@ namespace grpc {
 
 class Channel;
 class CompletionQueue;
-class Credentials;
+class CallCredentials;
 class RpcMethod;
 template <class R>
 class ClientReader;
@@ -244,7 +245,7 @@ class ClientContext {
   /// call.
   ///
   /// \see  https://github.com/grpc/grpc/blob/master/doc/grpc-auth-support.md
-  void set_credentials(const std::shared_ptr<Credentials>& creds) {
+  void set_credentials(const std::shared_ptr<CallCredentials>& creds) {
     creds_ = creds;
   }
 
@@ -315,10 +316,12 @@ class ClientContext {
 
   bool initial_metadata_received_;
   std::shared_ptr<Channel> channel_;
+  grpc::mutex mu_;
   grpc_call* call_;
+  bool call_canceled_;
   gpr_timespec deadline_;
   grpc::string authority_;
-  std::shared_ptr<Credentials> creds_;
+  std::shared_ptr<CallCredentials> creds_;
   mutable std::shared_ptr<const AuthContext> auth_context_;
   struct census_context* census_context_;
   std::multimap<grpc::string, grpc::string> send_initial_metadata_;
diff --git a/include/grpc++/create_channel.h b/include/grpc++/create_channel.h
index 196d2927a9a3c2b7faecf51905d1b49b75dc85d3..aff9c291c26d397e9b14c62186f7ca5b4eb43bf9 100644
--- a/include/grpc++/create_channel.h
+++ b/include/grpc++/create_channel.h
@@ -49,7 +49,8 @@ namespace grpc {
 /// an object or is invalid, a lame channel is returned.
 /// \param args Options for channel creation.
 std::shared_ptr<Channel> CreateChannel(
-    const grpc::string& target, const std::shared_ptr<Credentials>& creds);
+    const grpc::string& target,
+    const std::shared_ptr<ChannelCredentials>& creds);
 
 /// Create a new \em custom \a Channel pointing to \a target
 ///
@@ -61,7 +62,8 @@ std::shared_ptr<Channel> CreateChannel(
 /// an object or is invalid, a lame channel is returned.
 /// \param args Options for channel creation.
 std::shared_ptr<Channel> CreateCustomChannel(
-    const grpc::string& target, const std::shared_ptr<Credentials>& creds,
+    const grpc::string& target,
+    const std::shared_ptr<ChannelCredentials>& creds,
     const ChannelArguments& args);
 
 }  // namespace grpc
diff --git a/include/grpc++/security/credentials.h b/include/grpc++/security/credentials.h
index ff41bc597eb368544da896b1889d086af070cfbc..56827c0f21b7132d5a5b19f702045bf137378a36 100644
--- a/include/grpc++/security/credentials.h
+++ b/include/grpc++/security/credentials.h
@@ -45,37 +45,60 @@
 namespace grpc {
 class ChannelArguments;
 class Channel;
-class SecureCredentials;
-
-/// A credentials object encapsulates all the state needed by a client to
-/// authenticate with a server and make various assertions, e.g., about the
-/// client’s identity, role, or whether it is authorized to make a particular
-/// call.
+class SecureChannelCredentials;
+class CallCredentials;
+class SecureCallCredentials;
+
+/// A channel credentials object encapsulates all the state needed by a client
+/// to authenticate with a server for a given channel.
+/// It can make various assertions, e.g., about the client’s identity, role
+/// for all the calls on that channel.
 ///
 /// \see https://github.com/grpc/grpc/blob/master/doc/grpc-auth-support.md
-class Credentials : public GrpcLibrary {
+class ChannelCredentials : public GrpcLibrary {
  public:
-  ~Credentials() GRPC_OVERRIDE;
-
-  /// Apply this instance's credentials to \a call.
-  virtual bool ApplyToCall(grpc_call* call) = 0;
+  ~ChannelCredentials() GRPC_OVERRIDE;
 
  protected:
-  friend std::shared_ptr<Credentials> CompositeCredentials(
-      const std::shared_ptr<Credentials>& creds1,
-      const std::shared_ptr<Credentials>& creds2);
+  friend std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
+      const std::shared_ptr<ChannelCredentials>& channel_creds,
+      const std::shared_ptr<CallCredentials>& call_creds);
 
-  virtual SecureCredentials* AsSecureCredentials() = 0;
+  virtual SecureChannelCredentials* AsSecureCredentials() = 0;
 
  private:
   friend std::shared_ptr<Channel> CreateCustomChannel(
-      const grpc::string& target, const std::shared_ptr<Credentials>& creds,
+      const grpc::string& target,
+      const std::shared_ptr<ChannelCredentials>& creds,
       const ChannelArguments& args);
 
   virtual std::shared_ptr<Channel> CreateChannel(
       const grpc::string& target, const ChannelArguments& args) = 0;
 };
 
+/// A call credentials object encapsulates the state needed by a client to
+/// authenticate with a server for a given call on a channel.
+///
+/// \see https://github.com/grpc/grpc/blob/master/doc/grpc-auth-support.md
+class CallCredentials : public GrpcLibrary {
+ public:
+  ~CallCredentials() GRPC_OVERRIDE;
+
+  /// Apply this instance's credentials to \a call.
+  virtual bool ApplyToCall(grpc_call* call) = 0;
+
+ protected:
+  friend std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
+      const std::shared_ptr<ChannelCredentials>& channel_creds,
+      const std::shared_ptr<CallCredentials>& call_creds);
+
+  friend std::shared_ptr<CallCredentials> CompositeCallCredentials(
+      const std::shared_ptr<CallCredentials>& creds1,
+      const std::shared_ptr<CallCredentials>& creds2);
+
+  virtual SecureCallCredentials* AsSecureCredentials() = 0;
+};
+
 /// Options used to build SslCredentials.
 struct SslCredentialsOptions {
   /// The buffer containing the PEM encoding of the server root certificates. If
@@ -106,10 +129,10 @@ struct SslCredentialsOptions {
 /// Using these credentials to connect to any other service may result in this
 /// service being able to impersonate your client for requests to Google
 /// services.
-std::shared_ptr<Credentials> GoogleDefaultCredentials();
+std::shared_ptr<ChannelCredentials> GoogleDefaultCredentials();
 
 /// Builds SSL Credentials given SSL specific options
-std::shared_ptr<Credentials> SslCredentials(
+std::shared_ptr<ChannelCredentials> SslCredentials(
     const SslCredentialsOptions& options);
 
 /// Builds credentials for use when running in GCE
@@ -118,14 +141,14 @@ std::shared_ptr<Credentials> SslCredentials(
 /// Using these credentials to connect to any other service may result in this
 /// service being able to impersonate your client for requests to Google
 /// services.
-std::shared_ptr<Credentials> GoogleComputeEngineCredentials();
+std::shared_ptr<CallCredentials> GoogleComputeEngineCredentials();
 
 /// Builds Service Account JWT Access credentials.
 /// json_key is the JSON key string containing the client's private key.
 /// token_lifetime_seconds is the lifetime in seconds of each Json Web Token
 /// (JWT) created with this credentials. It should not exceed
 /// grpc_max_auth_token_lifetime or will be cropped to this value.
-std::shared_ptr<Credentials> ServiceAccountJWTAccessCredentials(
+std::shared_ptr<CallCredentials> ServiceAccountJWTAccessCredentials(
     const grpc::string& json_key, long token_lifetime_seconds);
 
 /// Builds refresh token credentials.
@@ -136,7 +159,7 @@ std::shared_ptr<Credentials> ServiceAccountJWTAccessCredentials(
 /// Using these credentials to connect to any other service may result in this
 /// service being able to impersonate your client for requests to Google
 /// services.
-std::shared_ptr<Credentials> GoogleRefreshTokenCredentials(
+std::shared_ptr<CallCredentials> GoogleRefreshTokenCredentials(
     const grpc::string& json_refresh_token);
 
 /// Builds access token credentials.
@@ -147,7 +170,7 @@ std::shared_ptr<Credentials> GoogleRefreshTokenCredentials(
 /// Using these credentials to connect to any other service may result in this
 /// service being able to impersonate your client for requests to Google
 /// services.
-std::shared_ptr<Credentials> AccessTokenCredentials(
+std::shared_ptr<CallCredentials> AccessTokenCredentials(
     const grpc::string& access_token);
 
 /// Builds IAM credentials.
@@ -156,17 +179,24 @@ std::shared_ptr<Credentials> AccessTokenCredentials(
 /// Using these credentials to connect to any other service may result in this
 /// service being able to impersonate your client for requests to Google
 /// services.
-std::shared_ptr<Credentials> GoogleIAMCredentials(
+std::shared_ptr<CallCredentials> GoogleIAMCredentials(
     const grpc::string& authorization_token,
     const grpc::string& authority_selector);
 
-/// Combines two credentials objects into a composite credentials
-std::shared_ptr<Credentials> CompositeCredentials(
-    const std::shared_ptr<Credentials>& creds1,
-    const std::shared_ptr<Credentials>& creds2);
+/// Combines a channel credentials and a call credentials into a composite
+/// channel credentials.
+std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
+      const std::shared_ptr<ChannelCredentials>& channel_creds,
+      const std::shared_ptr<CallCredentials>& call_creds);
+
+
+/// Combines two call credentials objects into a composite call credentials.
+std::shared_ptr<CallCredentials> CompositeCallCredentials(
+    const std::shared_ptr<CallCredentials>& creds1,
+    const std::shared_ptr<CallCredentials>& creds2);
 
 /// Credentials for an unencrypted, unauthenticated channel
-std::shared_ptr<Credentials> InsecureCredentials();
+std::shared_ptr<ChannelCredentials> InsecureChannelCredentials();
 
 // User defined metadata credentials.
 class MetadataCredentialsPlugin {
@@ -183,7 +213,7 @@ class MetadataCredentialsPlugin {
       std::multimap<grpc::string, grpc::string>* metadata) = 0;
 };
 
-std::shared_ptr<Credentials> MetadataCredentialsFromPlugin(
+std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
     std::unique_ptr<MetadataCredentialsPlugin> plugin);
 
 }  // namespace grpc
diff --git a/include/grpc++/support/channel_arguments.h b/include/grpc++/support/channel_arguments.h
index 9957712a9652c744b91a8f5b274bc4025959518e..cf8eab3b47286d89181a9e7a3cbadc483e189766 100644
--- a/include/grpc++/support/channel_arguments.h
+++ b/include/grpc++/support/channel_arguments.h
@@ -70,7 +70,8 @@ class ChannelArguments {
   void SetChannelArgs(grpc_channel_args* channel_args) const;
 
   // gRPC specific channel argument setters
-  /// Set target name override for SSL host name checking.
+  /// Set target name override for SSL host name checking. This option is for
+  /// testing only and should never be used in production.
   void SetSslTargetNameOverride(const grpc::string& name);
   // TODO(yangg) add flow control options
   /// Set the compression algorithm for the channel.
@@ -83,7 +84,7 @@ class ChannelArguments {
   void SetString(const grpc::string& key, const grpc::string& value);
 
  private:
-  friend class SecureCredentials;
+  friend class SecureChannelCredentials;
   friend class testing::ChannelArgumentsTest;
 
   // Returns empty string when it is not set.
diff --git a/include/grpc++/support/time.h b/include/grpc++/support/time.h
index 2d4196b93b7a3afb6d362d5629c6553bf7bec67d..e00e0d8e9172240d9f9e992e0065cdbfe0bd9658 100644
--- a/include/grpc++/support/time.h
+++ b/include/grpc++/support/time.h
@@ -35,6 +35,7 @@
 #define GRPCXX_SUPPORT_TIME_H
 
 #include <grpc++/support/config.h>
+#include <grpc/support/time.h>
 
 namespace grpc {
 
diff --git a/include/grpc/grpc_security.h b/include/grpc/grpc_security.h
index 7a442e2ace2e3ff6eb8a1a815b6d1fc597b51c22..c8da59331dbd8a4e126b87b580ba3d49026bd96f 100644
--- a/include/grpc/grpc_security.h
+++ b/include/grpc/grpc_security.h
@@ -41,15 +41,16 @@
 extern "C" {
 #endif
 
-/* --- grpc_credentials object. ---
+/* --- grpc_channel_credentials object. ---
 
-   A credentials object represents a way to authenticate a client.  */
+   A channel credentials object represents a way to authenticate a client on a
+   channel.  */
 
-typedef struct grpc_credentials grpc_credentials;
+typedef struct grpc_channel_credentials grpc_channel_credentials;
 
-/* Releases a credentials object.
+/* Releases a channel credentials object.
    The creator of the credentials object is responsible for its release. */
-void grpc_credentials_release(grpc_credentials *creds);
+void grpc_channel_credentials_release(grpc_channel_credentials *creds);
 
 /* Environment variable that points to the google default application
    credentials json key or refresh token. Used in the
@@ -59,7 +60,7 @@ void grpc_credentials_release(grpc_credentials *creds);
 /* Creates default credentials to connect to a google gRPC service.
    WARNING: Do NOT use this credentials to connect to a non-google service as
    this could result in an oauth2 token leak. */
-grpc_credentials *grpc_google_default_credentials_create(void);
+grpc_channel_credentials *grpc_google_default_credentials_create(void);
 
 /* Environment variable that points to the default SSL roots file. This file
    must be a PEM encoded file with all the roots such as the one that can be
@@ -88,19 +89,37 @@ typedef struct {
    - pem_key_cert_pair is a pointer on the object containing client's private
      key and certificate chain. This parameter can be NULL if the client does
      not have such a key/cert pair. */
-grpc_credentials *grpc_ssl_credentials_create(
+grpc_channel_credentials *grpc_ssl_credentials_create(
     const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
     void *reserved);
 
-/* Creates a composite credentials object. */
-grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
-                                                    grpc_credentials *creds2,
-                                                    void *reserved);
+/* --- grpc_call_credentials object.
+
+   A call credentials object represents a way to authenticate on a particular
+   call. These credentials can be composed with a channel credentials object
+   so that they are sent with every call on this channel.  */
+
+typedef struct grpc_call_credentials grpc_call_credentials;
+
+/* Releases a call credentials object.
+   The creator of the credentials object is responsible for its release. */
+void grpc_call_credentials_release(grpc_call_credentials *creds);
+
+/* Creates a composite channel credentials object. */
+grpc_channel_credentials *grpc_composite_channel_credentials_create(
+    grpc_channel_credentials *channel_creds, grpc_call_credentials *call_creds,
+    void *reserved);
+
+/* Creates a composite call credentials object. */
+grpc_call_credentials *grpc_composite_call_credentials_create(
+    grpc_call_credentials *creds1, grpc_call_credentials *creds2,
+    void *reserved);
 
 /* Creates a compute engine credentials object for connecting to Google.
    WARNING: Do NOT use this credentials to connect to a non-google service as
    this could result in an oauth2 token leak. */
-grpc_credentials *grpc_google_compute_engine_credentials_create(void *reserved);
+grpc_call_credentials *grpc_google_compute_engine_credentials_create(
+    void *reserved);
 
 extern const gpr_timespec grpc_max_auth_token_lifetime;
 
@@ -109,7 +128,7 @@ extern const gpr_timespec grpc_max_auth_token_lifetime;
    - token_lifetime is the lifetime of each Json Web Token (JWT) created with
      this credentials.  It should not exceed grpc_max_auth_token_lifetime or
      will be cropped to this value.  */
-grpc_credentials *grpc_service_account_jwt_access_credentials_create(
+grpc_call_credentials *grpc_service_account_jwt_access_credentials_create(
     const char *json_key, gpr_timespec token_lifetime, void *reserved);
 
 /* Creates an Oauth2 Refresh Token credentials object for connecting to Google.
@@ -118,16 +137,16 @@ grpc_credentials *grpc_service_account_jwt_access_credentials_create(
    this could result in an oauth2 token leak.
    - json_refresh_token is the JSON string containing the refresh token itself
      along with a client_id and client_secret. */
-grpc_credentials *grpc_google_refresh_token_credentials_create(
+grpc_call_credentials *grpc_google_refresh_token_credentials_create(
     const char *json_refresh_token, void *reserved);
 
 /* Creates an Oauth2 Access Token credentials with an access token that was
    aquired by an out of band mechanism. */
-grpc_credentials *grpc_access_token_credentials_create(const char *access_token,
-                                                       void *reserved);
+grpc_call_credentials *grpc_access_token_credentials_create(
+    const char *access_token, void *reserved);
 
 /* Creates an IAM credentials object for connecting to Google. */
-grpc_credentials *grpc_google_iam_credentials_create(
+grpc_call_credentials *grpc_google_iam_credentials_create(
     const char *authorization_token, const char *authority_selector,
     void *reserved);
 
@@ -168,13 +187,13 @@ typedef struct {
 } grpc_metadata_credentials_plugin;
 
 /* Creates a credentials object from a plugin. */
-grpc_credentials *grpc_metadata_credentials_create_from_plugin(
+grpc_call_credentials *grpc_metadata_credentials_create_from_plugin(
     grpc_metadata_credentials_plugin plugin, void *reserved);
 
 /* --- Secure channel creation. --- */
 
 /* Creates a secure channel using the passed-in credentials. */
-grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
+grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
                                          const char *target,
                                          const grpc_channel_args *args,
                                          void *reserved);
@@ -218,7 +237,7 @@ int grpc_server_add_secure_http2_port(grpc_server *server, const char *addr,
 /* Sets a credentials to a call. Can only be called on the client side before
    grpc_call_start_batch. */
 grpc_call_error grpc_call_set_credentials(grpc_call *call,
-                                          grpc_credentials *creds);
+                                          grpc_call_credentials *creds);
 
 /* --- Authentication Context. --- */
 
diff --git a/src/core/client_config/subchannel.c b/src/core/client_config/subchannel.c
index 49c2cf9a19ee3d9597e30e95409dc4ca3b71eaa4..b15a9033af803bd1261fbb083ddf5fea2fe19ede 100644
--- a/src/core/client_config/subchannel.c
+++ b/src/core/client_config/subchannel.c
@@ -697,10 +697,25 @@ static double generate_uniform_random_number(grpc_subchannel *c) {
 
 /* Update backoff_delta and next_attempt in subchannel */
 static void update_reconnect_parameters(grpc_subchannel *c) {
+  size_t i;
   gpr_int32 backoff_delta_millis, jitter;
   gpr_int32 max_backoff_millis =
       GRPC_SUBCHANNEL_RECONNECT_MAX_BACKOFF_SECONDS * 1000;
   double jitter_range;
+
+  if (c->args) {
+    for (i = 0; i < c->args->num_args; i++) {
+      if (0 == strcmp(c->args->args[i].key,
+                      "grpc.testing.fixed_reconnect_backoff")) {
+        GPR_ASSERT(c->args->args[i].type == GRPC_ARG_INTEGER);
+        c->next_attempt = gpr_time_add(
+            gpr_now(GPR_CLOCK_MONOTONIC),
+            gpr_time_from_millis(c->args->args[i].value.integer, GPR_TIMESPAN));
+        return;
+      }
+    }
+  }
+
   backoff_delta_millis =
       (gpr_int32)(gpr_time_to_millis(c->backoff_delta) *
                   GRPC_SUBCHANNEL_RECONNECT_BACKOFF_MULTIPLIER);
diff --git a/src/core/security/client_auth_filter.c b/src/core/security/client_auth_filter.c
index c780b65873cb02145d4a456b28bec165323096ef..be2522a7a01fbdd70662eb227815bafe0243716d 100644
--- a/src/core/security/client_auth_filter.c
+++ b/src/core/security/client_auth_filter.c
@@ -50,7 +50,7 @@
 
 /* We can have a per-call credentials. */
 typedef struct {
-  grpc_credentials *creds;
+  grpc_call_credentials *creds;
   grpc_mdstr *host;
   grpc_mdstr *method;
   /* pollset bound to this call; if we need to make external
@@ -143,39 +143,35 @@ static void send_security_metadata(grpc_exec_ctx *exec_ctx,
   channel_data *chand = elem->channel_data;
   grpc_client_security_context *ctx =
       (grpc_client_security_context *)op->context[GRPC_CONTEXT_SECURITY].value;
-  grpc_credentials *channel_creds =
+  grpc_call_credentials *channel_call_creds =
       chand->security_connector->request_metadata_creds;
-  int channel_creds_has_md =
-      (channel_creds != NULL) &&
-      grpc_credentials_has_request_metadata(channel_creds);
-  int call_creds_has_md = (ctx != NULL) && (ctx->creds != NULL) &&
-                          grpc_credentials_has_request_metadata(ctx->creds);
+  int call_creds_has_md = (ctx != NULL) && (ctx->creds != NULL);
 
-  if (!channel_creds_has_md && !call_creds_has_md) {
+  if (channel_call_creds == NULL && !call_creds_has_md) {
     /* Skip sending metadata altogether. */
     grpc_call_next_op(exec_ctx, elem, op);
     return;
   }
 
-  if (channel_creds_has_md && call_creds_has_md) {
-    calld->creds =
-        grpc_composite_credentials_create(channel_creds, ctx->creds, NULL);
+  if (channel_call_creds != NULL && call_creds_has_md) {
+    calld->creds = grpc_composite_call_credentials_create(channel_call_creds,
+                                                          ctx->creds, NULL);
     if (calld->creds == NULL) {
       bubble_up_error(exec_ctx, elem, GRPC_STATUS_INVALID_ARGUMENT,
                       "Incompatible credentials set on channel and call.");
       return;
     }
   } else {
-    calld->creds =
-        grpc_credentials_ref(call_creds_has_md ? ctx->creds : channel_creds);
+    calld->creds = grpc_call_credentials_ref(
+        call_creds_has_md ? ctx->creds : channel_call_creds);
   }
 
   build_service_url(chand->security_connector->base.url_scheme, calld);
   calld->op = *op; /* Copy op (originates from the caller's stack). */
   GPR_ASSERT(calld->pollset);
-  grpc_credentials_get_request_metadata(exec_ctx, calld->creds, calld->pollset,
-                                        calld->service_url,
-                                        on_credentials_metadata, elem);
+  grpc_call_credentials_get_request_metadata(exec_ctx, calld->creds,
+                                             calld->pollset, calld->service_url,
+                                             on_credentials_metadata, elem);
 }
 
 static void on_host_checked(grpc_exec_ctx *exec_ctx, void *user_data,
@@ -282,7 +278,7 @@ static void set_pollset(grpc_exec_ctx *exec_ctx, grpc_call_element *elem,
 static void destroy_call_elem(grpc_exec_ctx *exec_ctx,
                               grpc_call_element *elem) {
   call_data *calld = elem->call_data;
-  grpc_credentials_unref(calld->creds);
+  grpc_call_credentials_unref(calld->creds);
   if (calld->host != NULL) {
     GRPC_MDSTR_UNREF(calld->host);
   }
diff --git a/src/core/security/credentials.c b/src/core/security/credentials.c
index 2a8ffae5d7f08974782e9e2c24d928117005ca6e..3db531cd353461716f72c4a3430e3427df59ab5c 100644
--- a/src/core/security/credentials.c
+++ b/src/core/security/credentials.c
@@ -54,18 +54,18 @@
 /* -- Common. -- */
 
 struct grpc_credentials_metadata_request {
-  grpc_credentials *creds;
+  grpc_call_credentials *creds;
   grpc_credentials_metadata_cb cb;
   void *user_data;
 };
 
 static grpc_credentials_metadata_request *
-grpc_credentials_metadata_request_create(grpc_credentials *creds,
+grpc_credentials_metadata_request_create(grpc_call_credentials *creds,
                                          grpc_credentials_metadata_cb cb,
                                          void *user_data) {
   grpc_credentials_metadata_request *r =
       gpr_malloc(sizeof(grpc_credentials_metadata_request));
-  r->creds = grpc_credentials_ref(creds);
+  r->creds = grpc_call_credentials_ref(creds);
   r->cb = cb;
   r->user_data = user_data;
   return r;
@@ -73,44 +73,53 @@ grpc_credentials_metadata_request_create(grpc_credentials *creds,
 
 static void grpc_credentials_metadata_request_destroy(
     grpc_credentials_metadata_request *r) {
-  grpc_credentials_unref(r->creds);
+  grpc_call_credentials_unref(r->creds);
   gpr_free(r);
 }
 
-grpc_credentials *grpc_credentials_ref(grpc_credentials *creds) {
+grpc_channel_credentials *grpc_channel_credentials_ref(
+    grpc_channel_credentials *creds) {
   if (creds == NULL) return NULL;
   gpr_ref(&creds->refcount);
   return creds;
 }
 
-void grpc_credentials_unref(grpc_credentials *creds) {
+void grpc_channel_credentials_unref(grpc_channel_credentials *creds) {
   if (creds == NULL) return;
   if (gpr_unref(&creds->refcount)) {
-    creds->vtable->destruct(creds);
+    if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds);
     gpr_free(creds);
   }
 }
 
-void grpc_credentials_release(grpc_credentials *creds) {
-  GRPC_API_TRACE("grpc_credentials_release(creds=%p)", 1, (creds));
-  grpc_credentials_unref(creds);
+void grpc_channel_credentials_release(grpc_channel_credentials *creds) {
+  GRPC_API_TRACE("grpc_channel_credentials_release(creds=%p)", 1, (creds));
+  grpc_channel_credentials_unref(creds);
 }
 
-int grpc_credentials_has_request_metadata(grpc_credentials *creds) {
-  if (creds == NULL) return 0;
-  return creds->vtable->has_request_metadata(creds);
+grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds) {
+  if (creds == NULL) return NULL;
+  gpr_ref(&creds->refcount);
+  return creds;
 }
 
-int grpc_credentials_has_request_metadata_only(grpc_credentials *creds) {
-  if (creds == NULL) return 0;
-  return creds->vtable->has_request_metadata_only(creds);
+void grpc_call_credentials_unref(grpc_call_credentials *creds) {
+  if (creds == NULL) return;
+  if (gpr_unref(&creds->refcount)) {
+    if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds);
+    gpr_free(creds);
+  }
 }
 
-void grpc_credentials_get_request_metadata(
-    grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
+void grpc_call_credentials_release(grpc_call_credentials *creds) {
+  GRPC_API_TRACE("grpc_call_credentials_release(creds=%p)", 1, (creds));
+  grpc_call_credentials_unref(creds);
+}
+
+void grpc_call_credentials_get_request_metadata(
+    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
     const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
-  if (creds == NULL || !grpc_credentials_has_request_metadata(creds) ||
-      creds->vtable->get_request_metadata == NULL) {
+  if (creds == NULL || creds->vtable->get_request_metadata == NULL) {
     if (cb != NULL) {
       cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK);
     }
@@ -120,19 +129,17 @@ void grpc_credentials_get_request_metadata(
                                       user_data);
 }
 
-grpc_security_status grpc_credentials_create_security_connector(
-    grpc_credentials *creds, const char *target, const grpc_channel_args *args,
-    grpc_credentials *request_metadata_creds,
-    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+grpc_security_status grpc_channel_credentials_create_security_connector(
+    grpc_channel_credentials *channel_creds, const char *target,
+    const grpc_channel_args *args, grpc_channel_security_connector **sc,
+    grpc_channel_args **new_args) {
   *new_args = NULL;
-  if (creds == NULL || creds->vtable->create_security_connector == NULL ||
-      grpc_credentials_has_request_metadata_only(creds)) {
-    gpr_log(GPR_ERROR,
-            "Invalid credentials for creating a security connector.");
+  if (channel_creds == NULL) {
     return GRPC_SECURITY_ERROR;
   }
-  return creds->vtable->create_security_connector(
-      creds, target, args, request_metadata_creds, sc, new_args);
+  GPR_ASSERT(channel_creds->vtable->create_security_connector != NULL);
+  return channel_creds->vtable->create_security_connector(
+      channel_creds, NULL, target, args, sc, new_args);
 }
 
 grpc_server_credentials *grpc_server_credentials_ref(
@@ -145,7 +152,7 @@ grpc_server_credentials *grpc_server_credentials_ref(
 void grpc_server_credentials_unref(grpc_server_credentials *creds) {
   if (creds == NULL) return;
   if (gpr_unref(&creds->refcount)) {
-    creds->vtable->destruct(creds);
+    if (creds->vtable->destruct != NULL) creds->vtable->destruct(creds);
     if (creds->processor.destroy != NULL && creds->processor.state != NULL) {
       creds->processor.destroy(creds->processor.state);
     }
@@ -224,7 +231,7 @@ grpc_server_credentials *grpc_find_server_credentials_in_args(
 
 /* -- Ssl credentials. -- */
 
-static void ssl_destruct(grpc_credentials *creds) {
+static void ssl_destruct(grpc_channel_credentials *creds) {
   grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
   if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
   if (c->config.pem_private_key != NULL) gpr_free(c->config.pem_private_key);
@@ -253,15 +260,9 @@ static void ssl_server_destruct(grpc_server_credentials *creds) {
   if (c->config.pem_root_certs != NULL) gpr_free(c->config.pem_root_certs);
 }
 
-static int ssl_has_request_metadata(const grpc_credentials *creds) { return 0; }
-
-static int ssl_has_request_metadata_only(const grpc_credentials *creds) {
-  return 0;
-}
-
 static grpc_security_status ssl_create_security_connector(
-    grpc_credentials *creds, const char *target, const grpc_channel_args *args,
-    grpc_credentials *request_metadata_creds,
+    grpc_channel_credentials *creds, grpc_call_credentials *call_creds,
+    const char *target, const grpc_channel_args *args,
     grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
   grpc_ssl_credentials *c = (grpc_ssl_credentials *)creds;
   grpc_security_status status = GRPC_SECURITY_OK;
@@ -278,7 +279,7 @@ static grpc_security_status ssl_create_security_connector(
     }
   }
   status = grpc_ssl_channel_security_connector_create(
-      request_metadata_creds, &c->config, target, overridden_target_name, sc);
+      call_creds, &c->config, target, overridden_target_name, sc);
   if (status != GRPC_SECURITY_OK) {
     return status;
   }
@@ -295,9 +296,8 @@ static grpc_security_status ssl_server_create_security_connector(
   return grpc_ssl_server_security_connector_create(&c->config, sc);
 }
 
-static grpc_credentials_vtable ssl_vtable = {
-    ssl_destruct, ssl_has_request_metadata, ssl_has_request_metadata_only, NULL,
-    ssl_create_security_connector};
+static grpc_channel_credentials_vtable ssl_vtable = {
+    ssl_destruct, ssl_create_security_connector};
 
 static grpc_server_credentials_vtable ssl_server_vtable = {
     ssl_server_destruct, ssl_server_create_security_connector};
@@ -362,7 +362,7 @@ static void ssl_build_server_config(
   }
 }
 
-grpc_credentials *grpc_ssl_credentials_create(
+grpc_channel_credentials *grpc_ssl_credentials_create(
     const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
     void *reserved) {
   grpc_ssl_credentials *c = gpr_malloc(sizeof(grpc_ssl_credentials));
@@ -373,7 +373,7 @@ grpc_credentials *grpc_ssl_credentials_create(
       3, (pem_root_certs, pem_key_cert_pair, reserved));
   GPR_ASSERT(reserved == NULL);
   memset(c, 0, sizeof(grpc_ssl_credentials));
-  c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
+  c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL;
   c->base.vtable = &ssl_vtable;
   gpr_ref_init(&c->base.refcount, 1);
   ssl_build_config(pem_root_certs, pem_key_cert_pair, &c->config);
@@ -393,7 +393,7 @@ grpc_server_credentials *grpc_ssl_server_credentials_create(
           force_client_auth, reserved));
   GPR_ASSERT(reserved == NULL);
   memset(c, 0, sizeof(grpc_ssl_server_credentials));
-  c->base.type = GRPC_CREDENTIALS_TYPE_SSL;
+  c->base.type = GRPC_CHANNEL_CREDENTIALS_TYPE_SSL;
   gpr_ref_init(&c->base.refcount, 1);
   c->base.vtable = &ssl_server_vtable;
   ssl_build_server_config(pem_root_certs, pem_key_cert_pairs,
@@ -415,7 +415,7 @@ static void jwt_reset_cache(grpc_service_account_jwt_access_credentials *c) {
   c->cached.jwt_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
 }
 
-static void jwt_destruct(grpc_credentials *creds) {
+static void jwt_destruct(grpc_call_credentials *creds) {
   grpc_service_account_jwt_access_credentials *c =
       (grpc_service_account_jwt_access_credentials *)creds;
   grpc_auth_json_key_destruct(&c->key);
@@ -423,14 +423,8 @@ static void jwt_destruct(grpc_credentials *creds) {
   gpr_mu_destroy(&c->cache_mu);
 }
 
-static int jwt_has_request_metadata(const grpc_credentials *creds) { return 1; }
-
-static int jwt_has_request_metadata_only(const grpc_credentials *creds) {
-  return 1;
-}
-
 static void jwt_get_request_metadata(
-    grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
+    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
     const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
   grpc_service_account_jwt_access_credentials *c =
       (grpc_service_account_jwt_access_credentials *)creds;
@@ -483,11 +477,10 @@ static void jwt_get_request_metadata(
   }
 }
 
-static grpc_credentials_vtable jwt_vtable = {
-    jwt_destruct, jwt_has_request_metadata, jwt_has_request_metadata_only,
-    jwt_get_request_metadata, NULL};
+static grpc_call_credentials_vtable jwt_vtable = {jwt_destruct,
+                                                  jwt_get_request_metadata};
 
-grpc_credentials *
+grpc_call_credentials *
 grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
     grpc_auth_json_key key, gpr_timespec token_lifetime) {
   grpc_service_account_jwt_access_credentials *c;
@@ -497,7 +490,7 @@ grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
   }
   c = gpr_malloc(sizeof(grpc_service_account_jwt_access_credentials));
   memset(c, 0, sizeof(grpc_service_account_jwt_access_credentials));
-  c->base.type = GRPC_CREDENTIALS_TYPE_JWT;
+  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_JWT;
   gpr_ref_init(&c->base.refcount, 1);
   c->base.vtable = &jwt_vtable;
   c->key = key;
@@ -507,7 +500,7 @@ grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
   return &c->base;
 }
 
-grpc_credentials *grpc_service_account_jwt_access_credentials_create(
+grpc_call_credentials *grpc_service_account_jwt_access_credentials_create(
     const char *json_key, gpr_timespec token_lifetime, void *reserved) {
   GRPC_API_TRACE(
       "grpc_service_account_jwt_access_credentials_create("
@@ -524,7 +517,7 @@ grpc_credentials *grpc_service_account_jwt_access_credentials_create(
 
 /* -- Oauth2TokenFetcher credentials -- */
 
-static void oauth2_token_fetcher_destruct(grpc_credentials *creds) {
+static void oauth2_token_fetcher_destruct(grpc_call_credentials *creds) {
   grpc_oauth2_token_fetcher_credentials *c =
       (grpc_oauth2_token_fetcher_credentials *)creds;
   grpc_credentials_md_store_unref(c->access_token_md);
@@ -532,16 +525,6 @@ static void oauth2_token_fetcher_destruct(grpc_credentials *creds) {
   grpc_httpcli_context_destroy(&c->httpcli_context);
 }
 
-static int oauth2_token_fetcher_has_request_metadata(
-    const grpc_credentials *creds) {
-  return 1;
-}
-
-static int oauth2_token_fetcher_has_request_metadata_only(
-    const grpc_credentials *creds) {
-  return 1;
-}
-
 grpc_credentials_status
 grpc_oauth2_token_fetcher_credentials_parse_server_response(
     const grpc_httpcli_response *response, grpc_credentials_md_store **token_md,
@@ -659,8 +642,9 @@ static void on_oauth2_token_fetcher_http_response(
 }
 
 static void oauth2_token_fetcher_get_request_metadata(
-    grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
-    const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
+    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds,
+    grpc_pollset *pollset, const char *service_url,
+    grpc_credentials_metadata_cb cb, void *user_data) {
   grpc_oauth2_token_fetcher_credentials *c =
       (grpc_oauth2_token_fetcher_credentials *)creds;
   gpr_timespec refresh_threshold = gpr_time_from_seconds(
@@ -693,7 +677,7 @@ static void oauth2_token_fetcher_get_request_metadata(
 static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c,
                                       grpc_fetch_oauth2_func fetch_func) {
   memset(c, 0, sizeof(grpc_oauth2_token_fetcher_credentials));
-  c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
+  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2;
   gpr_ref_init(&c->base.refcount, 1);
   gpr_mu_init(&c->mu);
   c->token_expiration = gpr_inf_past(GPR_CLOCK_REALTIME);
@@ -703,10 +687,8 @@ static void init_oauth2_token_fetcher(grpc_oauth2_token_fetcher_credentials *c,
 
 /* -- GoogleComputeEngine credentials. -- */
 
-static grpc_credentials_vtable compute_engine_vtable = {
-    oauth2_token_fetcher_destruct, oauth2_token_fetcher_has_request_metadata,
-    oauth2_token_fetcher_has_request_metadata_only,
-    oauth2_token_fetcher_get_request_metadata, NULL};
+static grpc_call_credentials_vtable compute_engine_vtable = {
+    oauth2_token_fetcher_destruct, oauth2_token_fetcher_get_request_metadata};
 
 static void compute_engine_fetch_oauth2(
     grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req,
@@ -723,7 +705,7 @@ static void compute_engine_fetch_oauth2(
                    response_cb, metadata_req);
 }
 
-grpc_credentials *grpc_google_compute_engine_credentials_create(
+grpc_call_credentials *grpc_google_compute_engine_credentials_create(
     void *reserved) {
   grpc_oauth2_token_fetcher_credentials *c =
       gpr_malloc(sizeof(grpc_oauth2_token_fetcher_credentials));
@@ -737,17 +719,15 @@ grpc_credentials *grpc_google_compute_engine_credentials_create(
 
 /* -- GoogleRefreshToken credentials. -- */
 
-static void refresh_token_destruct(grpc_credentials *creds) {
+static void refresh_token_destruct(grpc_call_credentials *creds) {
   grpc_google_refresh_token_credentials *c =
       (grpc_google_refresh_token_credentials *)creds;
   grpc_auth_refresh_token_destruct(&c->refresh_token);
   oauth2_token_fetcher_destruct(&c->base.base);
 }
 
-static grpc_credentials_vtable refresh_token_vtable = {
-    refresh_token_destruct, oauth2_token_fetcher_has_request_metadata,
-    oauth2_token_fetcher_has_request_metadata_only,
-    oauth2_token_fetcher_get_request_metadata, NULL};
+static grpc_call_credentials_vtable refresh_token_vtable = {
+    refresh_token_destruct, oauth2_token_fetcher_get_request_metadata};
 
 static void refresh_token_fetch_oauth2(
     grpc_exec_ctx *exec_ctx, grpc_credentials_metadata_request *metadata_req,
@@ -773,7 +753,8 @@ static void refresh_token_fetch_oauth2(
   gpr_free(body);
 }
 
-grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token(
+grpc_call_credentials *
+grpc_refresh_token_credentials_create_from_auth_refresh_token(
     grpc_auth_refresh_token refresh_token) {
   grpc_google_refresh_token_credentials *c;
   if (!grpc_auth_refresh_token_is_valid(&refresh_token)) {
@@ -788,7 +769,7 @@ grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token(
   return &c->base.base;
 }
 
-grpc_credentials *grpc_google_refresh_token_credentials_create(
+grpc_call_credentials *grpc_google_refresh_token_credentials_create(
     const char *json_refresh_token, void *reserved) {
   GRPC_API_TRACE(
       "grpc_refresh_token_credentials_create(json_refresh_token=%s, "
@@ -801,20 +782,11 @@ grpc_credentials *grpc_google_refresh_token_credentials_create(
 
 /* -- Metadata-only credentials. -- */
 
-static void md_only_test_destruct(grpc_credentials *creds) {
+static void md_only_test_destruct(grpc_call_credentials *creds) {
   grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
   grpc_credentials_md_store_unref(c->md_store);
 }
 
-static int md_only_test_has_request_metadata(const grpc_credentials *creds) {
-  return 1;
-}
-
-static int md_only_test_has_request_metadata_only(
-    const grpc_credentials *creds) {
-  return 1;
-}
-
 static void on_simulated_token_fetch_done(void *user_data) {
   grpc_credentials_metadata_request *r =
       (grpc_credentials_metadata_request *)user_data;
@@ -827,7 +799,7 @@ static void on_simulated_token_fetch_done(void *user_data) {
 }
 
 static void md_only_test_get_request_metadata(
-    grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
+    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
     const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
   grpc_md_only_test_credentials *c = (grpc_md_only_test_credentials *)creds;
 
@@ -841,18 +813,15 @@ static void md_only_test_get_request_metadata(
   }
 }
 
-static grpc_credentials_vtable md_only_test_vtable = {
-    md_only_test_destruct, md_only_test_has_request_metadata,
-    md_only_test_has_request_metadata_only, md_only_test_get_request_metadata,
-    NULL};
+static grpc_call_credentials_vtable md_only_test_vtable = {
+    md_only_test_destruct, md_only_test_get_request_metadata};
 
-grpc_credentials *grpc_md_only_test_credentials_create(const char *md_key,
-                                                       const char *md_value,
-                                                       int is_async) {
+grpc_call_credentials *grpc_md_only_test_credentials_create(
+    const char *md_key, const char *md_value, int is_async) {
   grpc_md_only_test_credentials *c =
       gpr_malloc(sizeof(grpc_md_only_test_credentials));
   memset(c, 0, sizeof(grpc_md_only_test_credentials));
-  c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
+  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2;
   c->base.vtable = &md_only_test_vtable;
   gpr_ref_init(&c->base.refcount, 1);
   c->md_store = grpc_credentials_md_store_create(1);
@@ -863,34 +832,23 @@ grpc_credentials *grpc_md_only_test_credentials_create(const char *md_key,
 
 /* -- Oauth2 Access Token credentials. -- */
 
-static void access_token_destruct(grpc_credentials *creds) {
+static void access_token_destruct(grpc_call_credentials *creds) {
   grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
   grpc_credentials_md_store_unref(c->access_token_md);
 }
 
-static int access_token_has_request_metadata(const grpc_credentials *creds) {
-  return 1;
-}
-
-static int access_token_has_request_metadata_only(
-    const grpc_credentials *creds) {
-  return 1;
-}
-
 static void access_token_get_request_metadata(
-    grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
+    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
     const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
   grpc_access_token_credentials *c = (grpc_access_token_credentials *)creds;
   cb(exec_ctx, user_data, c->access_token_md->entries, 1, GRPC_CREDENTIALS_OK);
 }
 
-static grpc_credentials_vtable access_token_vtable = {
-    access_token_destruct, access_token_has_request_metadata,
-    access_token_has_request_metadata_only, access_token_get_request_metadata,
-    NULL};
+static grpc_call_credentials_vtable access_token_vtable = {
+    access_token_destruct, access_token_get_request_metadata};
 
-grpc_credentials *grpc_access_token_credentials_create(const char *access_token,
-                                                       void *reserved) {
+grpc_call_credentials *grpc_access_token_credentials_create(
+    const char *access_token, void *reserved) {
   grpc_access_token_credentials *c =
       gpr_malloc(sizeof(grpc_access_token_credentials));
   char *token_md_value;
@@ -900,7 +858,7 @@ grpc_credentials *grpc_access_token_credentials_create(const char *access_token,
       2, (access_token, reserved));
   GPR_ASSERT(reserved == NULL);
   memset(c, 0, sizeof(grpc_access_token_credentials));
-  c->base.type = GRPC_CREDENTIALS_TYPE_OAUTH2;
+  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_OAUTH2;
   c->base.vtable = &access_token_vtable;
   gpr_ref_init(&c->base.refcount, 1);
   c->access_token_md = grpc_credentials_md_store_create(1);
@@ -913,31 +871,11 @@ grpc_credentials *grpc_access_token_credentials_create(const char *access_token,
 
 /* -- Fake transport security credentials. -- */
 
-static void fake_transport_security_credentials_destruct(
-    grpc_credentials *creds) {
-  /* Nothing to do here. */
-}
-
-static void fake_transport_security_server_credentials_destruct(
-    grpc_server_credentials *creds) {
-  /* Nothing to do here. */
-}
-
-static int fake_transport_security_has_request_metadata(
-    const grpc_credentials *creds) {
-  return 0;
-}
-
-static int fake_transport_security_has_request_metadata_only(
-    const grpc_credentials *creds) {
-  return 0;
-}
-
 static grpc_security_status fake_transport_security_create_security_connector(
-    grpc_credentials *c, const char *target, const grpc_channel_args *args,
-    grpc_credentials *request_metadata_creds,
+    grpc_channel_credentials *c, grpc_call_credentials *call_creds,
+    const char *target, const grpc_channel_args *args,
     grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
-  *sc = grpc_fake_channel_security_connector_create(request_metadata_creds, 1);
+  *sc = grpc_fake_channel_security_connector_create(call_creds, 1);
   return GRPC_SECURITY_OK;
 }
 
@@ -948,21 +886,19 @@ fake_transport_security_server_create_security_connector(
   return GRPC_SECURITY_OK;
 }
 
-static grpc_credentials_vtable fake_transport_security_credentials_vtable = {
-    fake_transport_security_credentials_destruct,
-    fake_transport_security_has_request_metadata,
-    fake_transport_security_has_request_metadata_only, NULL,
-    fake_transport_security_create_security_connector};
+static grpc_channel_credentials_vtable
+    fake_transport_security_credentials_vtable = {
+        NULL, fake_transport_security_create_security_connector};
 
 static grpc_server_credentials_vtable
     fake_transport_security_server_credentials_vtable = {
-        fake_transport_security_server_credentials_destruct,
-        fake_transport_security_server_create_security_connector};
+        NULL, fake_transport_security_server_create_security_connector};
 
-grpc_credentials *grpc_fake_transport_security_credentials_create(void) {
-  grpc_credentials *c = gpr_malloc(sizeof(grpc_credentials));
-  memset(c, 0, sizeof(grpc_credentials));
-  c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
+grpc_channel_credentials *grpc_fake_transport_security_credentials_create(
+    void) {
+  grpc_channel_credentials *c = gpr_malloc(sizeof(grpc_channel_credentials));
+  memset(c, 0, sizeof(grpc_channel_credentials));
+  c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
   c->vtable = &fake_transport_security_credentials_vtable;
   gpr_ref_init(&c->refcount, 1);
   return c;
@@ -972,69 +908,46 @@ grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
     void) {
   grpc_server_credentials *c = gpr_malloc(sizeof(grpc_server_credentials));
   memset(c, 0, sizeof(grpc_server_credentials));
-  c->type = GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
+  c->type = GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY;
   gpr_ref_init(&c->refcount, 1);
   c->vtable = &fake_transport_security_server_credentials_vtable;
   return c;
 }
 
-/* -- Composite credentials. -- */
+/* -- Composite call credentials. -- */
 
 typedef struct {
-  grpc_composite_credentials *composite_creds;
+  grpc_composite_call_credentials *composite_creds;
   size_t creds_index;
   grpc_credentials_md_store *md_elems;
   char *service_url;
   void *user_data;
   grpc_pollset *pollset;
   grpc_credentials_metadata_cb cb;
-} grpc_composite_credentials_metadata_context;
+} grpc_composite_call_credentials_metadata_context;
 
-static void composite_destruct(grpc_credentials *creds) {
-  grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
+static void composite_call_destruct(grpc_call_credentials *creds) {
+  grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
   size_t i;
   for (i = 0; i < c->inner.num_creds; i++) {
-    grpc_credentials_unref(c->inner.creds_array[i]);
+    grpc_call_credentials_unref(c->inner.creds_array[i]);
   }
   gpr_free(c->inner.creds_array);
 }
 
-static int composite_has_request_metadata(const grpc_credentials *creds) {
-  const grpc_composite_credentials *c =
-      (const grpc_composite_credentials *)creds;
-  size_t i;
-  for (i = 0; i < c->inner.num_creds; i++) {
-    if (grpc_credentials_has_request_metadata(c->inner.creds_array[i])) {
-      return 1;
-    }
-  }
-  return 0;
-}
-
-static int composite_has_request_metadata_only(const grpc_credentials *creds) {
-  const grpc_composite_credentials *c =
-      (const grpc_composite_credentials *)creds;
-  size_t i;
-  for (i = 0; i < c->inner.num_creds; i++) {
-    if (!grpc_credentials_has_request_metadata_only(c->inner.creds_array[i])) {
-      return 0;
-    }
-  }
-  return 1;
-}
-
-static void composite_md_context_destroy(
-    grpc_composite_credentials_metadata_context *ctx) {
+static void composite_call_md_context_destroy(
+    grpc_composite_call_credentials_metadata_context *ctx) {
   grpc_credentials_md_store_unref(ctx->md_elems);
   if (ctx->service_url != NULL) gpr_free(ctx->service_url);
   gpr_free(ctx);
 }
 
-static void composite_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data,
-                                  grpc_credentials_md *md_elems, size_t num_md,
-                                  grpc_credentials_status status) {
-  grpc_composite_credentials_metadata_context *ctx =
-      (grpc_composite_credentials_metadata_context *)user_data;
+static void composite_call_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data,
+                                       grpc_credentials_md *md_elems,
+                                       size_t num_md,
+                                       grpc_credentials_status status) {
+  grpc_composite_call_credentials_metadata_context *ctx =
+      (grpc_composite_call_credentials_metadata_context *)user_data;
   if (status != GRPC_CREDENTIALS_OK) {
     ctx->cb(exec_ctx, ctx->user_data, NULL, 0, status);
     return;
@@ -1050,158 +963,111 @@ static void composite_metadata_cb(grpc_exec_ctx *exec_ctx, void *user_data,
   }
 
   /* See if we need to get some more metadata. */
-  while (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
-    grpc_credentials *inner_creds =
+  if (ctx->creds_index < ctx->composite_creds->inner.num_creds) {
+    grpc_call_credentials *inner_creds =
         ctx->composite_creds->inner.creds_array[ctx->creds_index++];
-    if (grpc_credentials_has_request_metadata(inner_creds)) {
-      grpc_credentials_get_request_metadata(exec_ctx, inner_creds, ctx->pollset,
-                                            ctx->service_url,
-                                            composite_metadata_cb, ctx);
-      return;
-    }
+    grpc_call_credentials_get_request_metadata(exec_ctx, inner_creds,
+                                               ctx->pollset, ctx->service_url,
+                                               composite_call_metadata_cb, ctx);
+    return;
   }
 
   /* We're done!. */
   ctx->cb(exec_ctx, ctx->user_data, ctx->md_elems->entries,
           ctx->md_elems->num_entries, GRPC_CREDENTIALS_OK);
-  composite_md_context_destroy(ctx);
+  composite_call_md_context_destroy(ctx);
 }
 
-static void composite_get_request_metadata(
-    grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
+static void composite_call_get_request_metadata(
+    grpc_exec_ctx *exec_ctx, grpc_call_credentials *creds, grpc_pollset *pollset,
     const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
-  grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
-  grpc_composite_credentials_metadata_context *ctx;
-  if (!grpc_credentials_has_request_metadata(creds)) {
-    cb(exec_ctx, user_data, NULL, 0, GRPC_CREDENTIALS_OK);
-    return;
-  }
-  ctx = gpr_malloc(sizeof(grpc_composite_credentials_metadata_context));
-  memset(ctx, 0, sizeof(grpc_composite_credentials_metadata_context));
+  grpc_composite_call_credentials *c = (grpc_composite_call_credentials *)creds;
+  grpc_composite_call_credentials_metadata_context *ctx;
+
+  ctx = gpr_malloc(sizeof(grpc_composite_call_credentials_metadata_context));
+  memset(ctx, 0, sizeof(grpc_composite_call_credentials_metadata_context));
   ctx->service_url = gpr_strdup(service_url);
   ctx->user_data = user_data;
   ctx->cb = cb;
   ctx->composite_creds = c;
   ctx->pollset = pollset;
   ctx->md_elems = grpc_credentials_md_store_create(c->inner.num_creds);
-  while (ctx->creds_index < c->inner.num_creds) {
-    grpc_credentials *inner_creds = c->inner.creds_array[ctx->creds_index++];
-    if (grpc_credentials_has_request_metadata(inner_creds)) {
-      grpc_credentials_get_request_metadata(exec_ctx, inner_creds, pollset,
-                                            service_url, composite_metadata_cb,
-                                            ctx);
-      return;
-    }
-  }
-  GPR_ASSERT(0); /* Should have exited before. */
+  grpc_call_credentials_get_request_metadata(
+      exec_ctx, c->inner.creds_array[ctx->creds_index++], pollset, service_url,
+      composite_call_metadata_cb, ctx);
 }
 
-static grpc_security_status composite_create_security_connector(
-    grpc_credentials *creds, const char *target, const grpc_channel_args *args,
-    grpc_credentials *request_metadata_creds,
-    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
-  grpc_composite_credentials *c = (grpc_composite_credentials *)creds;
-  if (c->connector_creds == NULL) {
-    gpr_log(GPR_ERROR,
-            "Cannot create security connector, missing connector credentials.");
-    return GRPC_SECURITY_ERROR;
-  }
-  return grpc_credentials_create_security_connector(c->connector_creds, target,
-                                                    args, creds, sc, new_args);
-}
+static grpc_call_credentials_vtable composite_call_credentials_vtable = {
+    composite_call_destruct, composite_call_get_request_metadata};
 
-static grpc_credentials_vtable composite_credentials_vtable = {
-    composite_destruct, composite_has_request_metadata,
-    composite_has_request_metadata_only, composite_get_request_metadata,
-    composite_create_security_connector};
-
-static grpc_credentials_array get_creds_array(grpc_credentials **creds_addr) {
-  grpc_credentials_array result;
-  grpc_credentials *creds = *creds_addr;
+static grpc_call_credentials_array get_creds_array(
+    grpc_call_credentials **creds_addr) {
+  grpc_call_credentials_array result;
+  grpc_call_credentials *creds = *creds_addr;
   result.creds_array = creds_addr;
   result.num_creds = 1;
-  if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0) {
-    result = *grpc_composite_credentials_get_credentials(creds);
+  if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) {
+    result = *grpc_composite_call_credentials_get_credentials(creds);
   }
   return result;
 }
 
-grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
-                                                    grpc_credentials *creds2,
-                                                    void *reserved) {
+grpc_call_credentials *grpc_composite_call_credentials_create(
+    grpc_call_credentials *creds1, grpc_call_credentials *creds2,
+    void *reserved) {
   size_t i;
   size_t creds_array_byte_size;
-  grpc_credentials_array creds1_array;
-  grpc_credentials_array creds2_array;
-  grpc_composite_credentials *c;
+  grpc_call_credentials_array creds1_array;
+  grpc_call_credentials_array creds2_array;
+  grpc_composite_call_credentials *c;
   GRPC_API_TRACE(
-      "grpc_composite_credentials_create(creds1=%p, creds2=%p, "
+      "grpc_composite_call_credentials_create(creds1=%p, creds2=%p, "
       "reserved=%p)",
       3, (creds1, creds2, reserved));
   GPR_ASSERT(reserved == NULL);
   GPR_ASSERT(creds1 != NULL);
   GPR_ASSERT(creds2 != NULL);
-  c = gpr_malloc(sizeof(grpc_composite_credentials));
-  memset(c, 0, sizeof(grpc_composite_credentials));
-  c->base.type = GRPC_CREDENTIALS_TYPE_COMPOSITE;
-  c->base.vtable = &composite_credentials_vtable;
+  c = gpr_malloc(sizeof(grpc_composite_call_credentials));
+  memset(c, 0, sizeof(grpc_composite_call_credentials));
+  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE;
+  c->base.vtable = &composite_call_credentials_vtable;
   gpr_ref_init(&c->base.refcount, 1);
   creds1_array = get_creds_array(&creds1);
   creds2_array = get_creds_array(&creds2);
   c->inner.num_creds = creds1_array.num_creds + creds2_array.num_creds;
-  creds_array_byte_size = c->inner.num_creds * sizeof(grpc_credentials *);
+  creds_array_byte_size = c->inner.num_creds * sizeof(grpc_call_credentials *);
   c->inner.creds_array = gpr_malloc(creds_array_byte_size);
   memset(c->inner.creds_array, 0, creds_array_byte_size);
   for (i = 0; i < creds1_array.num_creds; i++) {
-    grpc_credentials *cur_creds = creds1_array.creds_array[i];
-    if (!grpc_credentials_has_request_metadata_only(cur_creds)) {
-      if (c->connector_creds == NULL) {
-        c->connector_creds = cur_creds;
-      } else {
-        gpr_log(GPR_ERROR, "Cannot compose multiple connector credentials.");
-        goto fail;
-      }
-    }
-    c->inner.creds_array[i] = grpc_credentials_ref(cur_creds);
+    grpc_call_credentials *cur_creds = creds1_array.creds_array[i];
+    c->inner.creds_array[i] = grpc_call_credentials_ref(cur_creds);
   }
   for (i = 0; i < creds2_array.num_creds; i++) {
-    grpc_credentials *cur_creds = creds2_array.creds_array[i];
-    if (!grpc_credentials_has_request_metadata_only(cur_creds)) {
-      if (c->connector_creds == NULL) {
-        c->connector_creds = cur_creds;
-      } else {
-        gpr_log(GPR_ERROR, "Cannot compose multiple connector credentials.");
-        goto fail;
-      }
-    }
+    grpc_call_credentials *cur_creds = creds2_array.creds_array[i];
     c->inner.creds_array[i + creds1_array.num_creds] =
-        grpc_credentials_ref(cur_creds);
+        grpc_call_credentials_ref(cur_creds);
   }
   return &c->base;
-
-fail:
-  grpc_credentials_unref(&c->base);
-  return NULL;
 }
 
-const grpc_credentials_array *grpc_composite_credentials_get_credentials(
-    grpc_credentials *creds) {
-  const grpc_composite_credentials *c =
-      (const grpc_composite_credentials *)creds;
-  GPR_ASSERT(strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0);
+const grpc_call_credentials_array *
+grpc_composite_call_credentials_get_credentials(grpc_call_credentials *creds) {
+  const grpc_composite_call_credentials *c =
+      (const grpc_composite_call_credentials *)creds;
+  GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0);
   return &c->inner;
 }
 
-grpc_credentials *grpc_credentials_contains_type(
-    grpc_credentials *creds, const char *type,
-    grpc_credentials **composite_creds) {
+grpc_call_credentials *grpc_credentials_contains_type(
+    grpc_call_credentials *creds, const char *type,
+    grpc_call_credentials **composite_creds) {
   size_t i;
   if (strcmp(creds->type, type) == 0) {
     if (composite_creds != NULL) *composite_creds = NULL;
     return creds;
-  } else if (strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0) {
-    const grpc_credentials_array *inner_creds_array =
-        grpc_composite_credentials_get_credentials(creds);
+  } else if (strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0) {
+    const grpc_call_credentials_array *inner_creds_array =
+        grpc_composite_call_credentials_get_credentials(creds);
     for (i = 0; i < inner_creds_array->num_creds; i++) {
       if (strcmp(type, inner_creds_array->creds_array[i]->type) == 0) {
         if (composite_creds != NULL) *composite_creds = creds;
@@ -1214,30 +1080,26 @@ grpc_credentials *grpc_credentials_contains_type(
 
 /* -- IAM credentials. -- */
 
-static void iam_destruct(grpc_credentials *creds) {
+static void iam_destruct(grpc_call_credentials *creds) {
   grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds;
   grpc_credentials_md_store_unref(c->iam_md);
 }
 
-static int iam_has_request_metadata(const grpc_credentials *creds) { return 1; }
-
-static int iam_has_request_metadata_only(const grpc_credentials *creds) {
-  return 1;
-}
-
-static void iam_get_request_metadata(
-    grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
-    const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
+static void iam_get_request_metadata(grpc_exec_ctx *exec_ctx,
+                                     grpc_call_credentials *creds,
+                                     grpc_pollset *pollset,
+                                     const char *service_url,
+                                     grpc_credentials_metadata_cb cb,
+                                     void *user_data) {
   grpc_google_iam_credentials *c = (grpc_google_iam_credentials *)creds;
   cb(exec_ctx, user_data, c->iam_md->entries, c->iam_md->num_entries,
      GRPC_CREDENTIALS_OK);
 }
 
-static grpc_credentials_vtable iam_vtable = {
-    iam_destruct, iam_has_request_metadata, iam_has_request_metadata_only,
-    iam_get_request_metadata, NULL};
+static grpc_call_credentials_vtable iam_vtable = {iam_destruct,
+                                             iam_get_request_metadata};
 
-grpc_credentials *grpc_google_iam_credentials_create(
+grpc_call_credentials *grpc_google_iam_credentials_create(
     const char *token, const char *authority_selector, void *reserved) {
   grpc_google_iam_credentials *c;
   GRPC_API_TRACE(
@@ -1249,7 +1111,7 @@ grpc_credentials *grpc_google_iam_credentials_create(
   GPR_ASSERT(authority_selector != NULL);
   c = gpr_malloc(sizeof(grpc_google_iam_credentials));
   memset(c, 0, sizeof(grpc_google_iam_credentials));
-  c->base.type = GRPC_CREDENTIALS_TYPE_IAM;
+  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_IAM;
   c->base.vtable = &iam_vtable;
   gpr_ref_init(&c->base.refcount, 1);
   c->iam_md = grpc_credentials_md_store_create(2);
@@ -1267,21 +1129,13 @@ typedef struct {
   grpc_credentials_metadata_cb cb;
 } grpc_metadata_plugin_request;
 
-static void plugin_destruct(grpc_credentials *creds) {
+static void plugin_destruct(grpc_call_credentials *creds) {
   grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
   if (c->plugin.state != NULL && c->plugin.destroy != NULL) {
     c->plugin.destroy(c->plugin.state);
   }
 }
 
-static int plugin_has_request_metadata(const grpc_credentials *creds) {
-  return 1;
-}
-
-static int plugin_has_request_metadata_only(const grpc_credentials *creds) {
-  return 1;
-}
-
 static void plugin_md_request_metadata_ready(void *request,
                                              const grpc_metadata *md,
                                              size_t num_md,
@@ -1320,9 +1174,12 @@ static void plugin_md_request_metadata_ready(void *request,
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
-static void plugin_get_request_metadata(
-    grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
-    const char *service_url, grpc_credentials_metadata_cb cb, void *user_data) {
+static void plugin_get_request_metadata(grpc_exec_ctx *exec_ctx,
+                                        grpc_call_credentials *creds,
+                                        grpc_pollset *pollset,
+                                        const char *service_url,
+                                        grpc_credentials_metadata_cb cb,
+                                        void *user_data) {
   grpc_plugin_credentials *c = (grpc_plugin_credentials *)creds;
   if (c->plugin.get_metadata != NULL) {
     grpc_metadata_plugin_request *request = gpr_malloc(sizeof(*request));
@@ -1336,18 +1193,76 @@ static void plugin_get_request_metadata(
   }
 }
 
-static grpc_credentials_vtable plugin_vtable = {
-    plugin_destruct, plugin_has_request_metadata,
-    plugin_has_request_metadata_only, plugin_get_request_metadata, NULL};
+static grpc_call_credentials_vtable plugin_vtable = {
+    plugin_destruct, plugin_get_request_metadata};
 
-grpc_credentials *grpc_metadata_credentials_create_from_plugin(
+grpc_call_credentials *grpc_metadata_credentials_create_from_plugin(
     grpc_metadata_credentials_plugin plugin, void *reserved) {
   grpc_plugin_credentials *c = gpr_malloc(sizeof(*c));
+  GRPC_API_TRACE("grpc_metadata_credentials_create_from_plugin(reserved=%p)", 1,
+                 (reserved));
   GPR_ASSERT(reserved == NULL);
   memset(c, 0, sizeof(*c));
-  c->base.type = GRPC_CREDENTIALS_TYPE_METADATA_PLUGIN;
+  c->base.type = GRPC_CALL_CREDENTIALS_TYPE_METADATA_PLUGIN;
   c->base.vtable = &plugin_vtable;
   gpr_ref_init(&c->base.refcount, 1);
   c->plugin = plugin;
   return &c->base;
 }
+
+/* -- Composite channel credentials. -- */
+
+static void composite_channel_destruct(grpc_channel_credentials *creds) {
+  grpc_composite_channel_credentials *c =
+      (grpc_composite_channel_credentials *)creds;
+  grpc_channel_credentials_unref(c->inner_creds);
+  grpc_call_credentials_unref(c->call_creds);
+}
+
+static grpc_security_status composite_channel_create_security_connector(
+    grpc_channel_credentials *creds, grpc_call_credentials *call_creds,
+    const char *target, const grpc_channel_args *args,
+    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+  grpc_composite_channel_credentials *c =
+      (grpc_composite_channel_credentials *)creds;
+  grpc_security_status status = GRPC_SECURITY_ERROR;
+
+  GPR_ASSERT(c->inner_creds != NULL && c->call_creds != NULL &&
+             c->inner_creds->vtable != NULL &&
+             c->inner_creds->vtable->create_security_connector != NULL);
+  /* If we are passed a call_creds, create a call composite to pass it
+     downstream. */
+  if (call_creds != NULL) {
+    grpc_call_credentials *composite_call_creds =
+        grpc_composite_call_credentials_create(c->call_creds, call_creds, NULL);
+    status = c->inner_creds->vtable->create_security_connector(
+        c->inner_creds, composite_call_creds, target, args, sc, new_args);
+    grpc_call_credentials_unref(composite_call_creds);
+  } else {
+    status = c->inner_creds->vtable->create_security_connector(
+        c->inner_creds, c->call_creds, target, args, sc, new_args);
+  }
+  return status;
+}
+
+static grpc_channel_credentials_vtable composite_channel_credentials_vtable = {
+    composite_channel_destruct, composite_channel_create_security_connector};
+
+grpc_channel_credentials *grpc_composite_channel_credentials_create(
+    grpc_channel_credentials *channel_creds, grpc_call_credentials *call_creds,
+    void *reserved) {
+  grpc_composite_channel_credentials *c = gpr_malloc(sizeof(*c));
+  memset(c, 0, sizeof(*c));
+  GPR_ASSERT(channel_creds != NULL && call_creds != NULL && reserved == NULL);
+  GRPC_API_TRACE(
+      "grpc_composite_channel_credentials_create(channel_creds=%p, "
+      "call_creds=%p, reserved=%p)",
+      3, (channel_creds, call_creds, reserved));
+  c->base.type = channel_creds->type;
+  c->base.vtable = &composite_channel_credentials_vtable;
+  gpr_ref_init(&c->base.refcount, 1);
+  c->inner_creds = grpc_channel_credentials_ref(channel_creds);
+  c->call_creds = grpc_call_credentials_ref(call_creds);
+  return &c->base;
+}
+
diff --git a/src/core/security/credentials.h b/src/core/security/credentials.h
index c74beef0e4f2f9c30b56e6b0fcbb3d89f85549c8..559574d514e5a1082edec0e59036937c9dc1888c 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -54,15 +54,17 @@ typedef enum {
 
 #define GRPC_FAKE_TRANSPORT_SECURITY_TYPE "fake"
 
-#define GRPC_CREDENTIALS_TYPE_SSL "Ssl"
-#define GRPC_CREDENTIALS_TYPE_OAUTH2 "Oauth2"
-#define GRPC_CREDENTIALS_TYPE_METADATA_PLUGIN "Plugin"
-#define GRPC_CREDENTIALS_TYPE_JWT "Jwt"
-#define GRPC_CREDENTIALS_TYPE_IAM "Iam"
-#define GRPC_CREDENTIALS_TYPE_COMPOSITE "Composite"
-#define GRPC_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY "FakeTransportSecurity"
-
-#define GRPC_AUTHORIZATION_METADATA_KEY "Authorization"
+#define GRPC_CHANNEL_CREDENTIALS_TYPE_SSL "Ssl"
+#define GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY \
+  "FakeTransportSecurity"
+
+#define GRPC_CALL_CREDENTIALS_TYPE_OAUTH2 "Oauth2"
+#define GRPC_CALL_CREDENTIALS_TYPE_METADATA_PLUGIN "Plugin"
+#define GRPC_CALL_CREDENTIALS_TYPE_JWT "Jwt"
+#define GRPC_CALL_CREDENTIALS_TYPE_IAM "Iam"
+#define GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE "Composite"
+
+#define GRPC_AUTHORIZATION_METADATA_KEY "authorization"
 #define GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY \
   "x-goog-iam-authorization-token"
 #define GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY "x-goog-iam-authority-selector"
@@ -87,6 +89,41 @@ typedef enum {
 #define GRPC_REFRESH_TOKEN_POST_BODY_FORMAT_STRING \
   "client_id=%s&client_secret=%s&refresh_token=%s&grant_type=refresh_token"
 
+/* --- Google utils --- */
+
+/* It is the caller's responsibility to gpr_free the result if not NULL. */
+char *grpc_get_well_known_google_credentials_file_path(void);
+
+/* --- grpc_channel_credentials. --- */
+
+typedef struct {
+  void (*destruct)(grpc_channel_credentials *c);
+
+  grpc_security_status (*create_security_connector)(
+      grpc_channel_credentials *c, grpc_call_credentials *call_creds,
+      const char *target, const grpc_channel_args *args,
+      grpc_channel_security_connector **sc, grpc_channel_args **new_args);
+} grpc_channel_credentials_vtable;
+
+struct grpc_channel_credentials {
+  const grpc_channel_credentials_vtable *vtable;
+  const char *type;
+  gpr_refcount refcount;
+};
+
+grpc_channel_credentials *grpc_channel_credentials_ref(
+    grpc_channel_credentials *creds);
+void grpc_channel_credentials_unref(grpc_channel_credentials *creds);
+
+/* Creates a security connector for the channel. May also create new channel
+   args for the channel to be used in place of the passed in const args if
+   returned non NULL. In that case the caller is responsible for destroying
+   new_args after channel creation. */
+grpc_security_status grpc_channel_credentials_create_security_connector(
+    grpc_channel_credentials *creds, const char *target,
+    const grpc_channel_args *args, grpc_channel_security_connector **sc,
+    grpc_channel_args **new_args);
+
 /* --- grpc_credentials_md. --- */
 
 typedef struct {
@@ -113,16 +150,7 @@ grpc_credentials_md_store *grpc_credentials_md_store_ref(
     grpc_credentials_md_store *store);
 void grpc_credentials_md_store_unref(grpc_credentials_md_store *store);
 
-/* --- grpc_credentials. --- */
-
-/* Creates a fake transport security credentials object for testing. */
-grpc_credentials *grpc_fake_transport_security_credentials_create(void);
-/* Creates a fake server transport security credentials object for testing. */
-grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
-    void);
-
-/* It is the caller's responsibility to gpr_free the result if not NULL. */
-char *grpc_get_well_known_google_credentials_file_path(void);
+/* --- grpc_call_credentials. --- */
 
 typedef void (*grpc_credentials_metadata_cb)(grpc_exec_ctx *exec_ctx,
                                              void *user_data,
@@ -131,57 +159,44 @@ typedef void (*grpc_credentials_metadata_cb)(grpc_exec_ctx *exec_ctx,
                                              grpc_credentials_status status);
 
 typedef struct {
-  void (*destruct)(grpc_credentials *c);
-  int (*has_request_metadata)(const grpc_credentials *c);
-  int (*has_request_metadata_only)(const grpc_credentials *c);
-  void (*get_request_metadata)(grpc_exec_ctx *exec_ctx, grpc_credentials *c,
-                               grpc_pollset *pollset, const char *service_url,
+  void (*destruct)(grpc_call_credentials *c);
+  void (*get_request_metadata)(grpc_exec_ctx *exec_ctx,
+                               grpc_call_credentials *c, grpc_pollset *pollset,
+                               const char *service_url,
                                grpc_credentials_metadata_cb cb,
                                void *user_data);
-  grpc_security_status (*create_security_connector)(
-      grpc_credentials *c, const char *target, const grpc_channel_args *args,
-      grpc_credentials *request_metadata_creds,
-      grpc_channel_security_connector **sc, grpc_channel_args **new_args);
-} grpc_credentials_vtable;
+} grpc_call_credentials_vtable;
 
-struct grpc_credentials {
-  const grpc_credentials_vtable *vtable;
+struct grpc_call_credentials {
+  const grpc_call_credentials_vtable *vtable;
   const char *type;
   gpr_refcount refcount;
 };
 
-grpc_credentials *grpc_credentials_ref(grpc_credentials *creds);
-void grpc_credentials_unref(grpc_credentials *creds);
-int grpc_credentials_has_request_metadata(grpc_credentials *creds);
-int grpc_credentials_has_request_metadata_only(grpc_credentials *creds);
-void grpc_credentials_get_request_metadata(
-    grpc_exec_ctx *exec_ctx, grpc_credentials *creds, grpc_pollset *pollset,
-    const char *service_url, grpc_credentials_metadata_cb cb, void *user_data);
-
-/* Creates a security connector for the channel. May also create new channel
-   args for the channel to be used in place of the passed in const args if
-   returned non NULL. In that case the caller is responsible for destroying
-   new_args after channel creation. */
-grpc_security_status grpc_credentials_create_security_connector(
-    grpc_credentials *creds, const char *target, const grpc_channel_args *args,
-    grpc_credentials *request_metadata_creds,
-    grpc_channel_security_connector **sc, grpc_channel_args **new_args);
+grpc_call_credentials *grpc_call_credentials_ref(grpc_call_credentials *creds);
+void grpc_call_credentials_unref(grpc_call_credentials *creds);
+void grpc_call_credentials_get_request_metadata(grpc_exec_ctx *exec_ctx,
+                                                grpc_call_credentials *creds,
+                                                grpc_pollset *pollset,
+                                                const char *service_url,
+                                                grpc_credentials_metadata_cb cb,
+                                                void *user_data);
 
 typedef struct {
-  grpc_credentials **creds_array;
+  grpc_call_credentials **creds_array;
   size_t num_creds;
-} grpc_credentials_array;
+} grpc_call_credentials_array;
 
-const grpc_credentials_array *grpc_composite_credentials_get_credentials(
-    grpc_credentials *composite_creds);
+const grpc_call_credentials_array *grpc_composite_call_credentials_get_credentials(
+    grpc_call_credentials *composite_creds);
 
 /* Returns creds if creds is of the specified type or the inner creds of the
    specified type (if found), if the creds is of type COMPOSITE.
    If composite_creds is not NULL, *composite_creds will point to creds if of
    type COMPOSITE in case of success. */
-grpc_credentials *grpc_credentials_contains_type(
-    grpc_credentials *creds, const char *type,
-    grpc_credentials **composite_creds);
+grpc_call_credentials *grpc_credentials_contains_type(
+    grpc_call_credentials *creds, const char *type,
+    grpc_call_credentials **composite_creds);
 
 /* Exposed for testing only. */
 grpc_credentials_status
@@ -192,19 +207,19 @@ void grpc_flush_cached_google_default_credentials(void);
 
 /* Metadata-only credentials with the specified key and value where
    asynchronicity can be simulated for testing. */
-grpc_credentials *grpc_md_only_test_credentials_create(const char *md_key,
-                                                       const char *md_value,
-                                                       int is_async);
+grpc_call_credentials *grpc_md_only_test_credentials_create(
+    const char *md_key, const char *md_value, int is_async);
 
 /* Private constructor for jwt credentials from an already parsed json key.
    Takes ownership of the key. */
-grpc_credentials *
+grpc_call_credentials *
 grpc_service_account_jwt_access_credentials_create_from_auth_json_key(
     grpc_auth_json_key key, gpr_timespec token_lifetime);
 
 /* Private constructor for refresh token credentials from an already parsed
    refresh token. Takes ownership of the refresh token. */
-grpc_credentials *grpc_refresh_token_credentials_create_from_auth_refresh_token(
+grpc_call_credentials *
+grpc_refresh_token_credentials_create_from_auth_refresh_token(
     grpc_auth_refresh_token token);
 
 /* --- grpc_server_credentials. --- */
@@ -237,10 +252,18 @@ grpc_server_credentials *grpc_server_credentials_from_arg(const grpc_arg *arg);
 grpc_server_credentials *grpc_find_server_credentials_in_args(
     const grpc_channel_args *args);
 
+/* -- Fake transport security credentials. -- */
+
+/* Creates a fake transport security credentials object for testing. */
+grpc_channel_credentials *grpc_fake_transport_security_credentials_create(void);
+/* Creates a fake server transport security credentials object for testing. */
+grpc_server_credentials *grpc_fake_transport_security_server_credentials_create(
+    void);
+
 /* -- Ssl credentials. -- */
 
 typedef struct {
-  grpc_credentials base;
+  grpc_channel_credentials base;
   grpc_ssl_config config;
 } grpc_ssl_credentials;
 
@@ -249,10 +272,18 @@ typedef struct {
   grpc_ssl_server_config config;
 } grpc_ssl_server_credentials;
 
+/* -- Channel composite credentials. -- */
+
+typedef struct {
+  grpc_channel_credentials base;
+  grpc_channel_credentials *inner_creds;
+  grpc_call_credentials *call_creds;
+} grpc_composite_channel_credentials;
+
 /* -- Jwt credentials -- */
 
 typedef struct {
-  grpc_credentials base;
+  grpc_call_credentials base;
 
   /* Have a simple cache for now with just 1 entry. We could have a map based on
      the service_url for a more sophisticated one. */
@@ -283,7 +314,7 @@ typedef void (*grpc_fetch_oauth2_func)(grpc_exec_ctx *exec_ctx,
                                        gpr_timespec deadline);
 
 typedef struct {
-  grpc_credentials base;
+  grpc_call_credentials base;
   gpr_mu mu;
   grpc_credentials_md_store *access_token_md;
   gpr_timespec token_expiration;
@@ -301,14 +332,14 @@ typedef struct {
 /* -- Oauth2 Access Token credentials. -- */
 
 typedef struct {
-  grpc_credentials base;
+  grpc_call_credentials base;
   grpc_credentials_md_store *access_token_md;
 } grpc_access_token_credentials;
 
 /* --  Metadata-only Test credentials. -- */
 
 typedef struct {
-  grpc_credentials base;
+  grpc_call_credentials base;
   grpc_credentials_md_store *md_store;
   int is_async;
 } grpc_md_only_test_credentials;
@@ -316,22 +347,21 @@ typedef struct {
 /* -- GoogleIAM credentials. -- */
 
 typedef struct {
-  grpc_credentials base;
+  grpc_call_credentials base;
   grpc_credentials_md_store *iam_md;
 } grpc_google_iam_credentials;
 
 /* -- Composite credentials. -- */
 
 typedef struct {
-  grpc_credentials base;
-  grpc_credentials_array inner;
-  grpc_credentials *connector_creds;
-} grpc_composite_credentials;
+  grpc_call_credentials base;
+  grpc_call_credentials_array inner;
+} grpc_composite_call_credentials;
 
 /* -- Plugin credentials. -- */
 
 typedef struct {
-  grpc_credentials base;
+  grpc_call_credentials base;
   grpc_metadata_credentials_plugin plugin;
   grpc_credentials_md_store *plugin_md;
 } grpc_plugin_credentials;
diff --git a/src/core/security/google_default_credentials.c b/src/core/security/google_default_credentials.c
index 45135305b2883395bd5eef481408878252992ee4..e5a810f23cc1eae4441a26191f6cb72a9f61ad83 100644
--- a/src/core/security/google_default_credentials.c
+++ b/src/core/security/google_default_credentials.c
@@ -50,7 +50,7 @@
 
 /* -- Default credentials. -- */
 
-static grpc_credentials *default_credentials = NULL;
+static grpc_channel_credentials *default_credentials = NULL;
 static int compute_engine_detection_done = 0;
 static gpr_mu g_mu;
 static gpr_once g_once = GPR_ONCE_INIT;
@@ -138,11 +138,11 @@ static int is_stack_running_on_compute_engine(void) {
 }
 
 /* Takes ownership of creds_path if not NULL. */
-static grpc_credentials *create_default_creds_from_path(char *creds_path) {
+static grpc_call_credentials *create_default_creds_from_path(char *creds_path) {
   grpc_json *json = NULL;
   grpc_auth_json_key key;
   grpc_auth_refresh_token token;
-  grpc_credentials *result = NULL;
+  grpc_call_credentials *result = NULL;
   gpr_slice creds_data = gpr_empty_slice();
   int file_ok = 0;
   if (creds_path == NULL) goto end;
@@ -176,9 +176,9 @@ end:
   return result;
 }
 
-grpc_credentials *grpc_google_default_credentials_create(void) {
-  grpc_credentials *result = NULL;
-  int serving_cached_credentials = 0;
+grpc_channel_credentials *grpc_google_default_credentials_create(void) {
+  grpc_channel_credentials *result = NULL;
+  grpc_call_credentials *call_creds = NULL;
 
   GRPC_API_TRACE("grpc_google_default_credentials_create(void)", 0, ());
 
@@ -187,20 +187,19 @@ grpc_credentials *grpc_google_default_credentials_create(void) {
   gpr_mu_lock(&g_mu);
 
   if (default_credentials != NULL) {
-    result = grpc_credentials_ref(default_credentials);
-    serving_cached_credentials = 1;
+    result = grpc_channel_credentials_ref(default_credentials);
     goto end;
   }
 
   /* First, try the environment variable. */
-  result = create_default_creds_from_path(
+  call_creds = create_default_creds_from_path(
       gpr_getenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR));
-  if (result != NULL) goto end;
+  if (call_creds != NULL) goto end;
 
   /* Then the well-known file. */
-  result = create_default_creds_from_path(
+  call_creds = create_default_creds_from_path(
       grpc_get_well_known_google_credentials_file_path());
-  if (result != NULL) goto end;
+  if (call_creds != NULL) goto end;
 
   /* At last try to see if we're on compute engine (do the detection only once
      since it requires a network test). */
@@ -208,21 +207,27 @@ grpc_credentials *grpc_google_default_credentials_create(void) {
     int need_compute_engine_creds = is_stack_running_on_compute_engine();
     compute_engine_detection_done = 1;
     if (need_compute_engine_creds) {
-      result = grpc_google_compute_engine_credentials_create(NULL);
+      call_creds = grpc_google_compute_engine_credentials_create(NULL);
     }
   }
 
 end:
-  if (!serving_cached_credentials && result != NULL) {
-    /* Blend with default ssl credentials and add a global reference so that it
-       can be cached and re-served. */
-    grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL);
-    default_credentials = grpc_credentials_ref(
-        grpc_composite_credentials_create(ssl_creds, result, NULL));
-    GPR_ASSERT(default_credentials != NULL);
-    grpc_credentials_unref(ssl_creds);
-    grpc_credentials_unref(result);
-    result = default_credentials;
+  if (result == NULL) {
+    if (call_creds != NULL) {
+      /* Blend with default ssl credentials and add a global reference so that it
+         can be cached and re-served. */
+      grpc_channel_credentials *ssl_creds =
+          grpc_ssl_credentials_create(NULL, NULL, NULL);
+      default_credentials = grpc_channel_credentials_ref(
+          grpc_composite_channel_credentials_create(ssl_creds, call_creds,
+                                                    NULL));
+      GPR_ASSERT(default_credentials != NULL);
+      grpc_channel_credentials_unref(ssl_creds);
+      grpc_call_credentials_unref(call_creds);
+      result = default_credentials;
+    } else {
+      gpr_log(GPR_ERROR, "Could not create google default credentials.");
+    }
   }
   gpr_mu_unlock(&g_mu);
   return result;
@@ -232,7 +237,7 @@ void grpc_flush_cached_google_default_credentials(void) {
   gpr_once_init(&g_once, init_default_credentials);
   gpr_mu_lock(&g_mu);
   if (default_credentials != NULL) {
-    grpc_credentials_unref(default_credentials);
+    grpc_channel_credentials_unref(default_credentials);
     default_credentials = NULL;
   }
   gpr_mu_unlock(&g_mu);
diff --git a/src/core/security/security_connector.c b/src/core/security/security_connector.c
index 7c4cf6f04d66ca7cbf4943be8ab67da7f9d04933..8dbacdd35e5fc55252e3f0eedb6685570cd988e7 100644
--- a/src/core/security/security_connector.c
+++ b/src/core/security/security_connector.c
@@ -203,16 +203,6 @@ grpc_security_connector *grpc_find_security_connector_in_args(
   return NULL;
 }
 
-static int check_request_metadata_creds(grpc_credentials *creds) {
-  if (creds != NULL && !grpc_credentials_has_request_metadata(creds)) {
-    gpr_log(GPR_ERROR,
-            "Incompatible credentials for channel security connector: needs to "
-            "set request metadata.");
-    return 0;
-  }
-  return 1;
-}
-
 /* -- Fake implementation. -- */
 
 typedef struct {
@@ -222,7 +212,7 @@ typedef struct {
 
 static void fake_channel_destroy(grpc_security_connector *sc) {
   grpc_channel_security_connector *c = (grpc_channel_security_connector *)sc;
-  grpc_credentials_unref(c->request_metadata_creds);
+  grpc_call_credentials_unref(c->request_metadata_creds);
   GRPC_AUTH_CONTEXT_UNREF(sc->auth_context, "connector");
   gpr_free(sc);
 }
@@ -306,7 +296,8 @@ static grpc_security_connector_vtable fake_server_vtable = {
     fake_server_destroy, fake_server_do_handshake, fake_check_peer};
 
 grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
-    grpc_credentials *request_metadata_creds, int call_host_check_is_async) {
+    grpc_call_credentials *request_metadata_creds,
+    int call_host_check_is_async) {
   grpc_fake_channel_security_connector *c =
       gpr_malloc(sizeof(grpc_fake_channel_security_connector));
   memset(c, 0, sizeof(grpc_fake_channel_security_connector));
@@ -314,8 +305,8 @@ grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
   c->base.base.is_client_side = 1;
   c->base.base.url_scheme = GRPC_FAKE_SECURITY_URL_SCHEME;
   c->base.base.vtable = &fake_channel_vtable;
-  GPR_ASSERT(check_request_metadata_creds(request_metadata_creds));
-  c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds);
+  c->base.request_metadata_creds =
+      grpc_call_credentials_ref(request_metadata_creds);
   c->base.check_call_host = fake_channel_check_call_host;
   c->call_host_check_is_async = call_host_check_is_async;
   return &c->base;
@@ -349,7 +340,7 @@ typedef struct {
 static void ssl_channel_destroy(grpc_security_connector *sc) {
   grpc_ssl_channel_security_connector *c =
       (grpc_ssl_channel_security_connector *)sc;
-  grpc_credentials_unref(c->base.request_metadata_creds);
+  grpc_call_credentials_unref(c->base.request_metadata_creds);
   if (c->handshaker_factory != NULL) {
     tsi_ssl_handshaker_factory_destroy(c->handshaker_factory);
   }
@@ -580,7 +571,7 @@ size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs) {
 }
 
 grpc_security_status grpc_ssl_channel_security_connector_create(
-    grpc_credentials *request_metadata_creds, const grpc_ssl_config *config,
+    grpc_call_credentials *request_metadata_creds, const grpc_ssl_config *config,
     const char *target_name, const char *overridden_target_name,
     grpc_channel_security_connector **sc) {
   size_t num_alpn_protocols = grpc_chttp2_num_alpn_versions();
@@ -606,9 +597,6 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
     gpr_log(GPR_ERROR, "An ssl channel needs a config and a target name.");
     goto error;
   }
-  if (!check_request_metadata_creds(request_metadata_creds)) {
-    goto error;
-  }
   if (config->pem_root_certs == NULL) {
     pem_root_certs_size = grpc_get_default_ssl_roots(&pem_root_certs);
     if (pem_root_certs == NULL || pem_root_certs_size == 0) {
@@ -627,7 +615,8 @@ grpc_security_status grpc_ssl_channel_security_connector_create(
   c->base.base.vtable = &ssl_channel_vtable;
   c->base.base.is_client_side = 1;
   c->base.base.url_scheme = GRPC_SSL_URL_SCHEME;
-  c->base.request_metadata_creds = grpc_credentials_ref(request_metadata_creds);
+  c->base.request_metadata_creds =
+      grpc_call_credentials_ref(request_metadata_creds);
   c->base.check_call_host = ssl_channel_check_call_host;
   gpr_split_host_port(target_name, &c->target_name, &port);
   gpr_free(port);
diff --git a/src/core/security/security_connector.h b/src/core/security/security_connector.h
index 9218a3caab0adebb46487c0bcce8107b1fa58877..c5f00c5563784ed042327350e36611880058f89a 100644
--- a/src/core/security/security_connector.h
+++ b/src/core/security/security_connector.h
@@ -145,7 +145,7 @@ typedef struct grpc_channel_security_connector grpc_channel_security_connector;
 
 struct grpc_channel_security_connector {
   grpc_security_connector base; /* requires is_client_side to be non 0. */
-  grpc_credentials *request_metadata_creds;
+  grpc_call_credentials *request_metadata_creds;
   grpc_security_status (*check_call_host)(grpc_exec_ctx *exec_ctx,
                                           grpc_channel_security_connector *sc,
                                           const char *host,
@@ -167,7 +167,8 @@ grpc_security_status grpc_channel_security_connector_check_call_host(
 /* For TESTING ONLY!
    Creates a fake connector that emulates real channel security.  */
 grpc_channel_security_connector *grpc_fake_channel_security_connector_create(
-    grpc_credentials *request_metadata_creds, int call_host_check_is_async);
+    grpc_call_credentials *request_metadata_creds,
+    int call_host_check_is_async);
 
 /* For TESTING ONLY!
    Creates a fake connector that emulates real server security.  */
@@ -197,9 +198,9 @@ typedef struct {
   specific error code otherwise.
 */
 grpc_security_status grpc_ssl_channel_security_connector_create(
-    grpc_credentials *request_metadata_creds, const grpc_ssl_config *config,
-    const char *target_name, const char *overridden_target_name,
-    grpc_channel_security_connector **sc);
+    grpc_call_credentials *request_metadata_creds,
+    const grpc_ssl_config *config, const char *target_name,
+    const char *overridden_target_name, grpc_channel_security_connector **sc);
 
 /* Gets the default ssl roots. */
 size_t grpc_get_default_ssl_roots(const unsigned char **pem_root_certs);
diff --git a/src/core/security/security_context.c b/src/core/security/security_context.c
index ff3ad64d92d19f3ab7ffcd0f1fe6cbfb10c5de95..2068c97d78c22328708a1dd06b43b38a36829a6f 100644
--- a/src/core/security/security_context.c
+++ b/src/core/security/security_context.c
@@ -46,7 +46,7 @@
 /* --- grpc_call --- */
 
 grpc_call_error grpc_call_set_credentials(grpc_call *call,
-                                          grpc_credentials *creds) {
+                                          grpc_call_credentials *creds) {
   grpc_client_security_context *ctx = NULL;
   GRPC_API_TRACE("grpc_call_set_credentials(call=%p, creds=%p)", 2,
                  (call, creds));
@@ -54,20 +54,16 @@ grpc_call_error grpc_call_set_credentials(grpc_call *call,
     gpr_log(GPR_ERROR, "Method is client-side only.");
     return GRPC_CALL_ERROR_NOT_ON_SERVER;
   }
-  if (creds != NULL && !grpc_credentials_has_request_metadata_only(creds)) {
-    gpr_log(GPR_ERROR, "Incompatible credentials to set on a call.");
-    return GRPC_CALL_ERROR;
-  }
   ctx = (grpc_client_security_context *)grpc_call_context_get(
       call, GRPC_CONTEXT_SECURITY);
   if (ctx == NULL) {
     ctx = grpc_client_security_context_create();
-    ctx->creds = grpc_credentials_ref(creds);
+    ctx->creds = grpc_call_credentials_ref(creds);
     grpc_call_context_set(call, GRPC_CONTEXT_SECURITY, ctx,
                           grpc_client_security_context_destroy);
   } else {
-    grpc_credentials_unref(ctx->creds);
-    ctx->creds = grpc_credentials_ref(creds);
+    grpc_call_credentials_unref(ctx->creds);
+    ctx->creds = grpc_call_credentials_ref(creds);
   }
   return GRPC_CALL_OK;
 }
@@ -101,7 +97,7 @@ grpc_client_security_context *grpc_client_security_context_create(void) {
 
 void grpc_client_security_context_destroy(void *ctx) {
   grpc_client_security_context *c = (grpc_client_security_context *)ctx;
-  grpc_credentials_unref(c->creds);
+  grpc_call_credentials_unref(c->creds);
   GRPC_AUTH_CONTEXT_UNREF(c->auth_context, "client_security_context");
   gpr_free(ctx);
 }
diff --git a/src/core/security/security_context.h b/src/core/security/security_context.h
index 2bbdc4be973e3f66237663b83ea59e6a10536fa0..794258edbcb1470474e9154416d2ddf17a35a2d0 100644
--- a/src/core/security/security_context.h
+++ b/src/core/security/security_context.h
@@ -85,7 +85,7 @@ void grpc_auth_property_reset(grpc_auth_property *property);
    Internal client-side security context. */
 
 typedef struct {
-  grpc_credentials *creds;
+  grpc_call_credentials *creds;
   grpc_auth_context *auth_context;
 } grpc_client_security_context;
 
diff --git a/src/core/support/slice_buffer.c b/src/core/support/slice_buffer.c
index 17c0b6c0f652924bae22e6a19a5f331ce4c691de..856d3a24391e079500ce4ba7eb41db91ec600815 100644
--- a/src/core/support/slice_buffer.c
+++ b/src/core/support/slice_buffer.c
@@ -220,7 +220,7 @@ void gpr_slice_buffer_move_first(gpr_slice_buffer *src, size_t n,
     return;
   }
   src_idx = 0;
-  for (;;) {
+  while (src_idx < src->capacity) {
     gpr_slice slice = src->slices[src_idx];
     size_t slice_len = GPR_SLICE_LENGTH(slice);
     if (n > slice_len) {
diff --git a/src/core/support/time_win32.c b/src/core/support/time_win32.c
index bc0586d0691ff6d3e62445c9499a477eef8f5292..623a8d9233746fdb8a3629870d918fbce41267fd 100644
--- a/src/core/support/time_win32.c
+++ b/src/core/support/time_win32.c
@@ -66,14 +66,12 @@ gpr_timespec gpr_now(gpr_clock_type clock) {
       now_tv.tv_nsec = now_tb.millitm * 1000000;
       break;
     case GPR_CLOCK_MONOTONIC:
+    case GPR_CLOCK_PRECISE:
       QueryPerformanceCounter(&timestamp);
       now_dbl = (timestamp.QuadPart - g_start_time.QuadPart) * g_time_scale;
       now_tv.tv_sec = (time_t)now_dbl;
       now_tv.tv_nsec = (int)((now_dbl - (double)now_tv.tv_sec) * 1e9);
       break;
-    case GPR_CLOCK_PRECISE:
-      gpr_precise_clock_now(&now_tv);
-      break;
   }
   return now_tv;
 }
diff --git a/src/core/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c
index 1282ee99ed7ca18f315482ed763cb0d5527e6ce7..0dd0a3116944a0707ce0088d6d6921f50b327a0c 100644
--- a/src/core/surface/secure_channel_create.c
+++ b/src/core/surface/secure_channel_create.c
@@ -230,7 +230,7 @@ static const grpc_subchannel_factory_vtable subchannel_factory_vtable = {
    Asynchronously: - resolve target
                    - connect to it (trying alternatives as presented)
                    - perform handshakes */
-grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
+grpc_channel *grpc_secure_channel_create(grpc_channel_credentials *creds,
                                          const char *target,
                                          const grpc_channel_args *args,
                                          void *reserved) {
@@ -261,9 +261,9 @@ grpc_channel *grpc_secure_channel_create(grpc_credentials *creds,
         "Security connector exists in channel args.");
   }
 
-  if (grpc_credentials_create_security_connector(
-          creds, target, args, NULL, &security_connector,
-          &new_args_from_connector) != GRPC_SECURITY_OK) {
+  if (grpc_channel_credentials_create_security_connector(
+          creds, target, args, &security_connector, &new_args_from_connector) !=
+      GRPC_SECURITY_OK) {
     grpc_exec_ctx_finish(&exec_ctx);
     return grpc_lame_client_channel_create(
         target, GRPC_STATUS_INVALID_ARGUMENT,
diff --git a/src/core/surface/version.c b/src/core/surface/version.c
index e559d51448a4f91440e21e249392c79d91b02e60..962a72112a15c94d8e089a9efa3ec3f9ec400a67 100644
--- a/src/core/surface/version.c
+++ b/src/core/surface/version.c
@@ -36,4 +36,4 @@
 
 #include <grpc/grpc.h>
 
-const char *grpc_version_string(void) { return "0.11.0.0"; }
+const char *grpc_version_string(void) { return "0.12.0.0"; }
diff --git a/src/core/tsi/test_creds/server1.pem b/src/core/tsi/test_creds/server1.pem
index 8e582e571f643ca3fb6042a786c709a53f5afcf3..f3d43fcc5beadd98542abdaa32acfb555b807559 100644
--- a/src/core/tsi/test_creds/server1.pem
+++ b/src/core/tsi/test_creds/server1.pem
@@ -1,16 +1,16 @@
 -----BEGIN CERTIFICATE-----
-MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET
-MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
-dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5
-MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
-BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl
-c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs
-JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO
-RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30
-3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL
-BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6
-b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ
-KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS
-wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e
-aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s=
+MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
+MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx
+MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
+BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50
+ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco
+LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg
+zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd
+9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw
+CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy
+em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G
+CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6
+hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh
+y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8
 -----END CERTIFICATE-----
diff --git a/src/cpp/client/client_context.cc b/src/cpp/client/client_context.cc
index 574656a7e9b0a34ae1beb302732019b6fba34be3..9bb358b2339f123b58076ff0c6bc9fdb7dcbf153 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -48,6 +48,7 @@ namespace grpc {
 ClientContext::ClientContext()
     : initial_metadata_received_(false),
       call_(nullptr),
+      call_canceled_(false),
       deadline_(gpr_inf_future(GPR_CLOCK_REALTIME)),
       propagate_from_call_(nullptr) {}
 
@@ -72,6 +73,7 @@ void ClientContext::AddMetadata(const grpc::string& meta_key,
 
 void ClientContext::set_call(grpc_call* call,
                              const std::shared_ptr<Channel>& channel) {
+  grpc::unique_lock<grpc::mutex> lock(mu_);
   GPR_ASSERT(call_ == nullptr);
   call_ = call;
   channel_ = channel;
@@ -79,6 +81,9 @@ void ClientContext::set_call(grpc_call* call,
     grpc_call_cancel_with_status(call, GRPC_STATUS_CANCELLED,
                                  "Failed to set credentials to rpc.", nullptr);
   }
+  if (call_canceled_) {
+    grpc_call_cancel(call_, nullptr);
+  }
 }
 
 void ClientContext::set_compression_algorithm(
@@ -101,8 +106,11 @@ std::shared_ptr<const AuthContext> ClientContext::auth_context() const {
 }
 
 void ClientContext::TryCancel() {
+  grpc::unique_lock<grpc::mutex> lock(mu_);
   if (call_) {
     grpc_call_cancel(call_, nullptr);
+  } else {
+    call_canceled_ = true;
   }
 }
 
diff --git a/src/cpp/client/create_channel.cc b/src/cpp/client/create_channel.cc
index d2b2d30126c0d990fd46490e3af07237ca2e45ea..3bbca807d37e1ff6d790148ad74a75996c5d0397 100644
--- a/src/cpp/client/create_channel.cc
+++ b/src/cpp/client/create_channel.cc
@@ -44,12 +44,14 @@ namespace grpc {
 class ChannelArguments;
 
 std::shared_ptr<Channel> CreateChannel(
-    const grpc::string& target, const std::shared_ptr<Credentials>& creds) {
+    const grpc::string& target,
+    const std::shared_ptr<ChannelCredentials>& creds) {
   return CreateCustomChannel(target, creds, ChannelArguments());
 }
 
 std::shared_ptr<Channel> CreateCustomChannel(
-    const grpc::string& target, const std::shared_ptr<Credentials>& creds,
+    const grpc::string& target,
+    const std::shared_ptr<ChannelCredentials>& creds,
     const ChannelArguments& args) {
   GrpcLibrary init_lib;  // We need to call init in case of a bad creds.
   ChannelArguments cp_args = args;
diff --git a/src/cpp/client/credentials.cc b/src/cpp/client/credentials.cc
index 7a8149e9c7a06e31cb1715bdde76bc20303a66fb..0c08db11a9c5f87ae86ae33cf4763b15032a1b4c 100644
--- a/src/cpp/client/credentials.cc
+++ b/src/cpp/client/credentials.cc
@@ -35,6 +35,8 @@
 
 namespace grpc {
 
-Credentials::~Credentials() {}
+ChannelCredentials::~ChannelCredentials() {}
+
+CallCredentials::~CallCredentials() {}
 
 }  // namespace grpc
diff --git a/src/cpp/client/insecure_credentials.cc b/src/cpp/client/insecure_credentials.cc
index c476f3ce95b4e5feb57148d09d45b0ba25550c98..563fa9267d0145c21c8e60a4b14a258c2c41024b 100644
--- a/src/cpp/client/insecure_credentials.cc
+++ b/src/cpp/client/insecure_credentials.cc
@@ -43,7 +43,7 @@
 namespace grpc {
 
 namespace {
-class InsecureCredentialsImpl GRPC_FINAL : public Credentials {
+class InsecureChannelCredentialsImpl GRPC_FINAL : public ChannelCredentials {
  public:
   std::shared_ptr<grpc::Channel> CreateChannel(
       const string& target, const grpc::ChannelArguments& args) GRPC_OVERRIDE {
@@ -54,15 +54,13 @@ class InsecureCredentialsImpl GRPC_FINAL : public Credentials {
         grpc_insecure_channel_create(target.c_str(), &channel_args, nullptr));
   }
 
-  // InsecureCredentials should not be applied to a call.
-  bool ApplyToCall(grpc_call* call) GRPC_OVERRIDE { return false; }
-
-  SecureCredentials* AsSecureCredentials() GRPC_OVERRIDE { return nullptr; }
+  SecureChannelCredentials* AsSecureCredentials() GRPC_OVERRIDE { return nullptr; }
 };
 }  // namespace
 
-std::shared_ptr<Credentials> InsecureCredentials() {
-  return std::shared_ptr<Credentials>(new InsecureCredentialsImpl());
+std::shared_ptr<ChannelCredentials> InsecureChannelCredentials() {
+  return std::shared_ptr<ChannelCredentials>(
+      new InsecureChannelCredentialsImpl());
 }
 
 }  // namespace grpc
diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc
index 8299ebeb8a233499ec6bf9d8bc007e9b120fe44b..a1b9a3018e83ea8bfb669639d9858473124aa183 100644
--- a/src/cpp/client/secure_credentials.cc
+++ b/src/cpp/client/secure_credentials.cc
@@ -40,7 +40,7 @@
 
 namespace grpc {
 
-std::shared_ptr<grpc::Channel> SecureCredentials::CreateChannel(
+std::shared_ptr<grpc::Channel> SecureChannelCredentials::CreateChannel(
     const string& target, const grpc::ChannelArguments& args) {
   grpc_channel_args channel_args;
   args.SetChannelArgs(&channel_args);
@@ -50,96 +50,104 @@ std::shared_ptr<grpc::Channel> SecureCredentials::CreateChannel(
                                  nullptr));
 }
 
-bool SecureCredentials::ApplyToCall(grpc_call* call) {
+bool SecureCallCredentials::ApplyToCall(grpc_call* call) {
   return grpc_call_set_credentials(call, c_creds_) == GRPC_CALL_OK;
 }
 
 namespace {
-std::shared_ptr<Credentials> WrapCredentials(grpc_credentials* creds) {
-  return creds == nullptr
-             ? nullptr
-             : std::shared_ptr<Credentials>(new SecureCredentials(creds));
+std::shared_ptr<ChannelCredentials> WrapChannelCredentials(
+    grpc_channel_credentials* creds) {
+  return creds == nullptr ? nullptr : std::shared_ptr<ChannelCredentials>(
+                                          new SecureChannelCredentials(creds));
+}
+
+std::shared_ptr<CallCredentials> WrapCallCredentials(
+    grpc_call_credentials* creds) {
+  return creds == nullptr ? nullptr : std::shared_ptr<CallCredentials>(
+                                          new SecureCallCredentials(creds));
 }
 }  // namespace
 
-std::shared_ptr<Credentials> GoogleDefaultCredentials() {
+std::shared_ptr<ChannelCredentials> GoogleDefaultCredentials() {
   GrpcLibrary init;  // To call grpc_init().
-  return WrapCredentials(grpc_google_default_credentials_create());
+  return WrapChannelCredentials(grpc_google_default_credentials_create());
 }
 
 // Builds SSL Credentials given SSL specific options
-std::shared_ptr<Credentials> SslCredentials(
+std::shared_ptr<ChannelCredentials> SslCredentials(
     const SslCredentialsOptions& options) {
   GrpcLibrary init;  // To call grpc_init().
   grpc_ssl_pem_key_cert_pair pem_key_cert_pair = {
       options.pem_private_key.c_str(), options.pem_cert_chain.c_str()};
 
-  grpc_credentials* c_creds = grpc_ssl_credentials_create(
+  grpc_channel_credentials* c_creds = grpc_ssl_credentials_create(
       options.pem_root_certs.empty() ? nullptr : options.pem_root_certs.c_str(),
       options.pem_private_key.empty() ? nullptr : &pem_key_cert_pair, nullptr);
-  return WrapCredentials(c_creds);
+  return WrapChannelCredentials(c_creds);
 }
 
 // Builds credentials for use when running in GCE
-std::shared_ptr<Credentials> GoogleComputeEngineCredentials() {
+std::shared_ptr<CallCredentials> GoogleComputeEngineCredentials() {
   GrpcLibrary init;  // To call grpc_init().
-  return WrapCredentials(
+  return WrapCallCredentials(
       grpc_google_compute_engine_credentials_create(nullptr));
 }
 
 // Builds JWT credentials.
-std::shared_ptr<Credentials> ServiceAccountJWTAccessCredentials(
+std::shared_ptr<CallCredentials> ServiceAccountJWTAccessCredentials(
     const grpc::string& json_key, long token_lifetime_seconds) {
   GrpcLibrary init;  // To call grpc_init().
   if (token_lifetime_seconds <= 0) {
     gpr_log(GPR_ERROR,
             "Trying to create JWTCredentials with non-positive lifetime");
-    return WrapCredentials(nullptr);
+    return WrapCallCredentials(nullptr);
   }
   gpr_timespec lifetime =
       gpr_time_from_seconds(token_lifetime_seconds, GPR_TIMESPAN);
-  return WrapCredentials(grpc_service_account_jwt_access_credentials_create(
+  return WrapCallCredentials(grpc_service_account_jwt_access_credentials_create(
       json_key.c_str(), lifetime, nullptr));
 }
 
 // Builds refresh token credentials.
-std::shared_ptr<Credentials> GoogleRefreshTokenCredentials(
+std::shared_ptr<CallCredentials> GoogleRefreshTokenCredentials(
     const grpc::string& json_refresh_token) {
   GrpcLibrary init;  // To call grpc_init().
-  return WrapCredentials(grpc_google_refresh_token_credentials_create(
+  return WrapCallCredentials(grpc_google_refresh_token_credentials_create(
       json_refresh_token.c_str(), nullptr));
 }
 
 // Builds access token credentials.
-std::shared_ptr<Credentials> AccessTokenCredentials(
+std::shared_ptr<CallCredentials> AccessTokenCredentials(
     const grpc::string& access_token) {
   GrpcLibrary init;  // To call grpc_init().
-  return WrapCredentials(
+  return WrapCallCredentials(
       grpc_access_token_credentials_create(access_token.c_str(), nullptr));
 }
 
 // Builds IAM credentials.
-std::shared_ptr<Credentials> GoogleIAMCredentials(
+std::shared_ptr<CallCredentials> GoogleIAMCredentials(
     const grpc::string& authorization_token,
     const grpc::string& authority_selector) {
   GrpcLibrary init;  // To call grpc_init().
-  return WrapCredentials(grpc_google_iam_credentials_create(
+  return WrapCallCredentials(grpc_google_iam_credentials_create(
       authorization_token.c_str(), authority_selector.c_str(), nullptr));
 }
 
-// Combines two credentials objects into a composite credentials.
-std::shared_ptr<Credentials> CompositeCredentials(
-    const std::shared_ptr<Credentials>& creds1,
-    const std::shared_ptr<Credentials>& creds2) {
-  // Note that we are not saving shared_ptrs to the two credentials
-  // passed in here. This is OK because the underlying C objects (i.e.,
-  // creds1 and creds2) into grpc_composite_credentials_create will see their
-  // refcounts incremented.
-  SecureCredentials* s1 = creds1->AsSecureCredentials();
-  SecureCredentials* s2 = creds2->AsSecureCredentials();
-  if (s1 && s2) {
-    return WrapCredentials(grpc_composite_credentials_create(
-        s1->GetRawCreds(), s2->GetRawCreds(), nullptr));
+// Combines one channel credentials and one call credentials into a channel
+// composite credentials.
+std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
+    const std::shared_ptr<ChannelCredentials>& channel_creds,
+    const std::shared_ptr<CallCredentials>& call_creds) {
+  // Note that we are not saving shared_ptrs to the two credentials passed in
+  // here. This is OK because the underlying C objects (i.e., channel_creds and
+  // call_creds) into grpc_composite_credentials_create will see their refcounts
+  // incremented.
+  SecureChannelCredentials* s_channel_creds =
+      channel_creds->AsSecureCredentials();
+  SecureCallCredentials* s_call_creds = call_creds->AsSecureCredentials();
+  if (s_channel_creds && s_call_creds) {
+    return WrapChannelCredentials(grpc_composite_channel_credentials_create(
+        s_channel_creds->GetRawCreds(), s_call_creds->GetRawCreds(), nullptr));
   }
   return nullptr;
 }
@@ -193,7 +201,7 @@ MetadataCredentialsPluginWrapper::MetadataCredentialsPluginWrapper(
     std::unique_ptr<MetadataCredentialsPlugin> plugin)
     : thread_pool_(CreateDefaultThreadPool()), plugin_(std::move(plugin)) {}
 
-std::shared_ptr<Credentials> MetadataCredentialsFromPlugin(
+std::shared_ptr<CallCredentials> MetadataCredentialsFromPlugin(
     std::unique_ptr<MetadataCredentialsPlugin> plugin) {
   GrpcLibrary init;  // To call grpc_init().
   MetadataCredentialsPluginWrapper* wrapper =
@@ -201,7 +209,7 @@ std::shared_ptr<Credentials> MetadataCredentialsFromPlugin(
   grpc_metadata_credentials_plugin c_plugin = {
       MetadataCredentialsPluginWrapper::GetMetadata,
       MetadataCredentialsPluginWrapper::Destroy, wrapper};
-  return WrapCredentials(
+  return WrapCallCredentials(
       grpc_metadata_credentials_create_from_plugin(c_plugin, nullptr));
 }
 
diff --git a/src/cpp/client/secure_credentials.h b/src/cpp/client/secure_credentials.h
index d354827725a30c77290e8dbf2f500759baee3f4b..b241761a7c46470eb39ac191b79a554666c2435b 100644
--- a/src/cpp/client/secure_credentials.h
+++ b/src/cpp/client/secure_credentials.h
@@ -43,21 +43,40 @@
 
 namespace grpc {
 
-class SecureCredentials GRPC_FINAL : public Credentials {
+class SecureChannelCredentials GRPC_FINAL : public ChannelCredentials {
  public:
-  explicit SecureCredentials(grpc_credentials* c_creds) : c_creds_(c_creds) {}
-  ~SecureCredentials() GRPC_OVERRIDE { grpc_credentials_release(c_creds_); }
-  grpc_credentials* GetRawCreds() { return c_creds_; }
-  bool ApplyToCall(grpc_call* call) GRPC_OVERRIDE;
+  explicit SecureChannelCredentials(grpc_channel_credentials* c_creds)
+      : c_creds_(c_creds) {}
+  ~SecureChannelCredentials() GRPC_OVERRIDE {
+    grpc_channel_credentials_release(c_creds_);
+  }
+  grpc_channel_credentials* GetRawCreds() { return c_creds_; }
 
   std::shared_ptr<grpc::Channel> CreateChannel(
       const string& target, const grpc::ChannelArguments& args) GRPC_OVERRIDE;
-  SecureCredentials* AsSecureCredentials() GRPC_OVERRIDE { return this; }
+  SecureChannelCredentials* AsSecureCredentials() GRPC_OVERRIDE { return this; }
 
  private:
-  grpc_credentials* const c_creds_;
+  grpc_channel_credentials* const c_creds_;
 };
 
+class SecureCallCredentials GRPC_FINAL : public CallCredentials {
+ public:
+  explicit SecureCallCredentials(grpc_call_credentials* c_creds)
+      : c_creds_(c_creds) {}
+  ~SecureCallCredentials() GRPC_OVERRIDE {
+    grpc_call_credentials_release(c_creds_);
+  }
+  grpc_call_credentials* GetRawCreds() { return c_creds_; }
+
+  bool ApplyToCall(grpc_call* call) GRPC_OVERRIDE;
+  SecureCallCredentials* AsSecureCredentials() GRPC_OVERRIDE { return this; }
+
+ private:
+  grpc_call_credentials* const c_creds_;
+};
+
+
 class MetadataCredentialsPluginWrapper GRPC_FINAL {
  public:
   static void Destroy(void* wrapper);
diff --git a/src/csharp/Grpc.Core.Tests/FakeCredentials.cs b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs
index 87d55cd276ae5601b84a1dd3b7db97dd4aac5fe7..144b8320b9df5c276fe8a19f773e4a61593cc1de 100644
--- a/src/csharp/Grpc.Core.Tests/FakeCredentials.cs
+++ b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs
@@ -57,7 +57,7 @@ namespace Grpc.Core.Tests
             get { return composable; }
         }
 
-        internal override CredentialsSafeHandle ToNativeCredentials()
+        internal override ChannelCredentialsSafeHandle ToNativeCredentials()
         {
             return null;
         }
@@ -65,7 +65,7 @@ namespace Grpc.Core.Tests
 
     internal class FakeCallCredentials : CallCredentials
     {
-        internal override CredentialsSafeHandle ToNativeCredentials()
+        internal override CallCredentialsSafeHandle ToNativeCredentials()
         {
             return null;
         }
diff --git a/src/csharp/Grpc.Core/CallCredentials.cs b/src/csharp/Grpc.Core/CallCredentials.cs
index 400a9825de220029cb0d2e5fbf39acf4345f2041..5ea179dfea152353b051902c03dde16cc2c477da 100644
--- a/src/csharp/Grpc.Core/CallCredentials.cs
+++ b/src/csharp/Grpc.Core/CallCredentials.cs
@@ -78,7 +78,7 @@ namespace Grpc.Core
         /// Creates native object for the credentials.
         /// </summary>
         /// <returns>The native credentials.</returns>
-        internal abstract CredentialsSafeHandle ToNativeCredentials();
+        internal abstract CallCredentialsSafeHandle ToNativeCredentials();
     }
 
     /// <summary>
@@ -98,7 +98,7 @@ namespace Grpc.Core
             this.interceptor = Preconditions.CheckNotNull(interceptor);
         }
 
-        internal override CredentialsSafeHandle ToNativeCredentials()
+        internal override CallCredentialsSafeHandle ToNativeCredentials()
         {
             NativeMetadataCredentialsPlugin plugin = new NativeMetadataCredentialsPlugin(interceptor);
             return plugin.Credentials;
@@ -123,14 +123,14 @@ namespace Grpc.Core
             this.credentials = new List<CallCredentials>(credentials);
         }
 
-        internal override CredentialsSafeHandle ToNativeCredentials()
+        internal override CallCredentialsSafeHandle ToNativeCredentials()
         {
             return ToNativeRecursive(0);
         }
 
         // Recursive descent makes managing lifetime of intermediate CredentialSafeHandle instances easier.
         // In practice, we won't usually see composites from more than two credentials anyway.
-        private CredentialsSafeHandle ToNativeRecursive(int startIndex)
+        private CallCredentialsSafeHandle ToNativeRecursive(int startIndex)
         {
             if (startIndex == credentials.Count - 1)
             {
@@ -140,7 +140,7 @@ namespace Grpc.Core
             using (var cred1 = credentials[startIndex].ToNativeCredentials())
             using (var cred2 = ToNativeRecursive(startIndex + 1))
             {
-                var nativeComposite = CredentialsSafeHandle.CreateComposite(cred1, cred2);
+                var nativeComposite = CallCredentialsSafeHandle.CreateComposite(cred1, cred2);
                 if (nativeComposite.IsInvalid)
                 {
                     throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials.");
diff --git a/src/csharp/Grpc.Core/Channel.cs b/src/csharp/Grpc.Core/Channel.cs
index 6b99055d4c893cb7b92d703d11b4bdbc2360fb71..f5eec969f5ed5b4ee91b4a74f39d304b7736a51f 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -75,8 +75,8 @@ namespace Grpc.Core
             this.options = options != null ? new List<ChannelOption>(options) : new List<ChannelOption>();
 
             EnsureUserAgentChannelOption(this.options);
-            using (CredentialsSafeHandle nativeCredentials = credentials.ToNativeCredentials())
-            using (ChannelArgsSafeHandle nativeChannelArgs = ChannelOptions.CreateChannelArgs(this.options))
+            using (var nativeCredentials = credentials.ToNativeCredentials())
+            using (var nativeChannelArgs = ChannelOptions.CreateChannelArgs(this.options))
             {
                 if (nativeCredentials != null)
                 {
diff --git a/src/csharp/Grpc.Core/ChannelCredentials.cs b/src/csharp/Grpc.Core/ChannelCredentials.cs
index 9d2bcdabe843abc2799d04fcdf7d581de37cbe62..5d96958e7c082f1871f585a29af91883b7276022 100644
--- a/src/csharp/Grpc.Core/ChannelCredentials.cs
+++ b/src/csharp/Grpc.Core/ChannelCredentials.cs
@@ -76,7 +76,7 @@ namespace Grpc.Core
         /// should be created.
         /// </summary>
         /// <returns>The native credentials.</returns>
-        internal abstract CredentialsSafeHandle ToNativeCredentials();
+        internal abstract ChannelCredentialsSafeHandle ToNativeCredentials();
 
         /// <summary>
         /// Returns <c>true</c> if this credential type allows being composed by <c>CompositeCredentials</c>.
@@ -88,7 +88,7 @@ namespace Grpc.Core
 
         private sealed class InsecureCredentialsImpl : ChannelCredentials
         {
-            internal override CredentialsSafeHandle ToNativeCredentials()
+            internal override ChannelCredentialsSafeHandle ToNativeCredentials()
             {
                 return null;
             }
@@ -160,9 +160,9 @@ namespace Grpc.Core
             get { return true; }
         }
 
-        internal override CredentialsSafeHandle ToNativeCredentials()
+        internal override ChannelCredentialsSafeHandle ToNativeCredentials()
         {
-            return CredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair);
+            return ChannelCredentialsSafeHandle.CreateSslCredentials(rootCertificates, keyCertificatePair);
         }
     }
 
@@ -188,12 +188,12 @@ namespace Grpc.Core
             Preconditions.CheckArgument(channelCredentials.IsComposable, "Supplied channel credentials do not allow composition.");
         }
 
-        internal override CredentialsSafeHandle ToNativeCredentials()
+        internal override ChannelCredentialsSafeHandle ToNativeCredentials()
         {
-            using (var cred1 = channelCredentials.ToNativeCredentials())
-            using (var cred2 = callCredentials.ToNativeCredentials())
+            using (var channelCreds = channelCredentials.ToNativeCredentials())
+            using (var callCreds = callCredentials.ToNativeCredentials())
             {
-                var nativeComposite = CredentialsSafeHandle.CreateComposite(cred1, cred2);
+                var nativeComposite = ChannelCredentialsSafeHandle.CreateComposite(channelCreds, callCreds);
                 if (nativeComposite.IsInvalid)
                 {
                     throw new ArgumentException("Error creating native composite credentials. Likely, this is because you are trying to compose incompatible credentials.");
diff --git a/src/csharp/Grpc.Core/Grpc.Core.csproj b/src/csharp/Grpc.Core/Grpc.Core.csproj
index 0aab7bdd8ad2a4591bf12ef21bdcfff3523e1aec..c4f799297d6688cd0314fea7a8b8079353e7f9d9 100644
--- a/src/csharp/Grpc.Core/Grpc.Core.csproj
+++ b/src/csharp/Grpc.Core/Grpc.Core.csproj
@@ -80,7 +80,6 @@
     <Compile Include="ServerServiceDefinition.cs" />
     <Compile Include="Utils\AsyncStreamExtensions.cs" />
     <Compile Include="Utils\BenchmarkUtil.cs" />
-    <Compile Include="Internal\CredentialsSafeHandle.cs" />
     <Compile Include="ChannelCredentials.cs" />
     <Compile Include="Internal\ChannelArgsSafeHandle.cs" />
     <Compile Include="Internal\AsyncCompletion.cs" />
@@ -119,6 +118,8 @@
     <Compile Include="CompressionLevel.cs" />
     <Compile Include="WriteOptions.cs" />
     <Compile Include="ContextPropagationToken.cs" />
+    <Compile Include="Internal\CallCredentialsSafeHandle.cs" />
+    <Compile Include="Internal\ChannelCredentialsSafeHandle.cs" />
     <Compile Include="Profiling\ProfilerEntry.cs" />
     <Compile Include="Profiling\ProfilerScope.cs" />
     <Compile Include="Profiling\IProfiler.cs" />
@@ -157,4 +158,4 @@
   <ItemGroup>
     <Folder Include="Profiling\" />
   </ItemGroup>
-</Project>
\ No newline at end of file
+</Project>
diff --git a/src/csharp/Grpc.Core/Internal/CallCredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallCredentialsSafeHandle.cs
new file mode 100644
index 0000000000000000000000000000000000000000..3678c7dd86f413a4b8cfa920e1b51c7c0306e074
--- /dev/null
+++ b/src/csharp/Grpc.Core/Internal/CallCredentialsSafeHandle.cs
@@ -0,0 +1,64 @@
+#region Copyright notice and license
+// Copyright 2015, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+//     * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+#endregion
+using System;
+using System.Runtime.InteropServices;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Grpc.Core.Internal
+{
+    /// <summary>
+    /// grpc_call_credentials from <c>grpc/grpc_security.h</c>
+    /// </summary>
+    internal class CallCredentialsSafeHandle : SafeHandleZeroIsInvalid
+    {
+        [DllImport("grpc_csharp_ext.dll")]
+        static extern CallCredentialsSafeHandle grpcsharp_composite_call_credentials_create(CallCredentialsSafeHandle creds1, CallCredentialsSafeHandle creds2);
+
+        [DllImport("grpc_csharp_ext.dll")]
+        static extern void grpcsharp_call_credentials_release(IntPtr credentials);
+
+        private CallCredentialsSafeHandle()
+        {
+        }
+
+        public static CallCredentialsSafeHandle CreateComposite(CallCredentialsSafeHandle creds1, CallCredentialsSafeHandle creds2)
+        {
+            return grpcsharp_composite_call_credentials_create(creds1, creds2);
+        }
+
+        protected override bool ReleaseHandle()
+        {
+            grpcsharp_call_credentials_release(handle);
+            return true;
+        }
+    }
+}
diff --git a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
index ddeedebd117f650f99702c759d22bd5a824110ae..ad2e2919b7411911c0b64c1fdca92b86b5df71e0 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -100,7 +100,7 @@ namespace Grpc.Core.Internal
             BatchContextSafeHandle ctx, MetadataArraySafeHandle metadataArray);
 
         [DllImport("grpc_csharp_ext.dll")]
-        static extern GRPCCallError grpcsharp_call_set_credentials(CallSafeHandle call, CredentialsSafeHandle credentials);
+        static extern GRPCCallError grpcsharp_call_set_credentials(CallSafeHandle call, CallCredentialsSafeHandle credentials);
 
         [DllImport("grpc_csharp_ext.dll")]
         static extern CStringSafeHandle grpcsharp_call_get_peer(CallSafeHandle call);
@@ -117,7 +117,7 @@ namespace Grpc.Core.Internal
             this.completionRegistry = completionRegistry;
         }
 
-        public void SetCredentials(CredentialsSafeHandle credentials)
+        public void SetCredentials(CallCredentialsSafeHandle credentials)
         {
             grpcsharp_call_set_credentials(this, credentials).CheckOk();
         }
diff --git a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelCredentialsSafeHandle.cs
similarity index 68%
rename from src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
rename to src/csharp/Grpc.Core/Internal/ChannelCredentialsSafeHandle.cs
index bab45108e02a060952e8b96dcc64cd807dd63779..8a58c64478e44726a52cabbaae3b04a308e94bc2 100644
--- a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ChannelCredentialsSafeHandle.cs
@@ -36,31 +36,31 @@ using System.Threading.Tasks;
 namespace Grpc.Core.Internal
 {
     /// <summary>
-    /// grpc_credentials from <c>grpc/grpc_security.h</c>
+    /// grpc_channel_credentials from <c>grpc/grpc_security.h</c>
     /// </summary>
-    internal class CredentialsSafeHandle : SafeHandleZeroIsInvalid
+    internal class ChannelCredentialsSafeHandle : SafeHandleZeroIsInvalid
     {
         [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
-        static extern CredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey);
+        static extern ChannelCredentialsSafeHandle grpcsharp_ssl_credentials_create(string pemRootCerts, string keyCertPairCertChain, string keyCertPairPrivateKey);
 
         [DllImport("grpc_csharp_ext.dll")]
-        static extern CredentialsSafeHandle grpcsharp_composite_credentials_create(CredentialsSafeHandle creds1, CredentialsSafeHandle creds2);
+        static extern ChannelCredentialsSafeHandle grpcsharp_composite_channel_credentials_create(ChannelCredentialsSafeHandle channelCreds, CallCredentialsSafeHandle callCreds);
 
         [DllImport("grpc_csharp_ext.dll")]
-        static extern void grpcsharp_credentials_release(IntPtr credentials);
+        static extern void grpcsharp_channel_credentials_release(IntPtr credentials);
 
-        private CredentialsSafeHandle()
+        private ChannelCredentialsSafeHandle()
         {
         }
 
-        public static CredentialsSafeHandle CreateNullCredentials()
+        public static ChannelCredentialsSafeHandle CreateNullCredentials()
         {
-            var creds = new CredentialsSafeHandle();
+            var creds = new ChannelCredentialsSafeHandle();
             creds.SetHandle(IntPtr.Zero);
             return creds;
         }
 
-        public static CredentialsSafeHandle CreateSslCredentials(string pemRootCerts, KeyCertificatePair keyCertPair)
+        public static ChannelCredentialsSafeHandle CreateSslCredentials(string pemRootCerts, KeyCertificatePair keyCertPair)
         {
             if (keyCertPair != null)
             {
@@ -72,14 +72,14 @@ namespace Grpc.Core.Internal
             }
         }
 
-        public static CredentialsSafeHandle CreateComposite(CredentialsSafeHandle creds1, CredentialsSafeHandle creds2)
+        public static ChannelCredentialsSafeHandle CreateComposite(ChannelCredentialsSafeHandle channelCreds, CallCredentialsSafeHandle callCreds)
         {
-            return grpcsharp_composite_credentials_create(creds1, creds2);
+            return grpcsharp_composite_channel_credentials_create(channelCreds, callCreds);
         }
 
         protected override bool ReleaseHandle()
         {
-            grpcsharp_credentials_release(handle);
+            grpcsharp_channel_credentials_release(handle);
             return true;
         }
     }
diff --git a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
index 5f9169bcb2f02b70878a4fd871379c3c7eca6fca..b3aa27c40fa1c17c63a25110e8f57311dab63746 100644
--- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
@@ -45,7 +45,7 @@ namespace Grpc.Core.Internal
         static extern ChannelSafeHandle grpcsharp_insecure_channel_create(string target, ChannelArgsSafeHandle channelArgs);
 
         [DllImport("grpc_csharp_ext.dll")]
-        static extern ChannelSafeHandle grpcsharp_secure_channel_create(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs);
+        static extern ChannelSafeHandle grpcsharp_secure_channel_create(ChannelCredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs);
 
         [DllImport("grpc_csharp_ext.dll")]
         static extern CallSafeHandle grpcsharp_channel_create_call(ChannelSafeHandle channel, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline);
@@ -75,7 +75,7 @@ namespace Grpc.Core.Internal
             return grpcsharp_insecure_channel_create(target, channelArgs);
         }
 
-        public static ChannelSafeHandle CreateSecure(CredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs)
+        public static ChannelSafeHandle CreateSecure(ChannelCredentialsSafeHandle credentials, string target, ChannelArgsSafeHandle channelArgs)
         {
             // Increment reference count for the native gRPC environment to make sure we don't do grpc_shutdown() before destroying the server handle.
             // Doing so would make object finalizer crash if we end up abandoning the handle.
@@ -83,7 +83,7 @@ namespace Grpc.Core.Internal
             return grpcsharp_secure_channel_create(credentials, target, channelArgs);
         }
 
-        public CallSafeHandle CreateCall(CompletionRegistry registry, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline, CredentialsSafeHandle credentials)
+        public CallSafeHandle CreateCall(CompletionRegistry registry, CallSafeHandle parentCall, ContextPropagationFlags propagationMask, CompletionQueueSafeHandle cq, string method, string host, Timespec deadline, CallCredentialsSafeHandle credentials)
         {
             using (Profilers.ForCurrentThread().NewScope("ChannelSafeHandle.CreateCall"))
             {
diff --git a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
index f76492cba4a90b9b7151a52bafe5f026e62c9cfe..2a571cd6c9862b4f0f6a4daa33fbeeb8522569a6 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
@@ -46,7 +46,7 @@ namespace Grpc.Core.Internal
         static readonly ILogger Logger = GrpcEnvironment.Logger.ForType<NativeMetadataCredentialsPlugin>();
 
         [DllImport("grpc_csharp_ext.dll")]
-        static extern CredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor);
+        static extern CallCredentialsSafeHandle grpcsharp_metadata_credentials_create_from_plugin(NativeMetadataInterceptor interceptor);
         
         [DllImport("grpc_csharp_ext.dll", CharSet = CharSet.Ansi)]
         static extern void grpcsharp_metadata_credentials_notify_from_plugin(IntPtr callbackPtr, IntPtr userData, MetadataArraySafeHandle metadataArray, StatusCode statusCode, string errorDetails);
@@ -54,7 +54,7 @@ namespace Grpc.Core.Internal
         AsyncAuthInterceptor interceptor;
         GCHandle gcHandle;
         NativeMetadataInterceptor nativeInterceptor;
-        CredentialsSafeHandle credentials;
+        CallCredentialsSafeHandle credentials;
 
         public NativeMetadataCredentialsPlugin(AsyncAuthInterceptor interceptor)
         {
@@ -66,7 +66,7 @@ namespace Grpc.Core.Internal
             this.credentials = grpcsharp_metadata_credentials_create_from_plugin(nativeInterceptor);
         }
 
-        public CredentialsSafeHandle Credentials
+        public CallCredentialsSafeHandle Credentials
         {
             get { return credentials; }
         }
diff --git a/src/csharp/Grpc.IntegrationTesting/data/server1.pem b/src/csharp/Grpc.IntegrationTesting/data/server1.pem
index 8e582e571f643ca3fb6042a786c709a53f5afcf3..f3d43fcc5beadd98542abdaa32acfb555b807559 100644
--- a/src/csharp/Grpc.IntegrationTesting/data/server1.pem
+++ b/src/csharp/Grpc.IntegrationTesting/data/server1.pem
@@ -1,16 +1,16 @@
 -----BEGIN CERTIFICATE-----
-MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET
-MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
-dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5
-MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
-BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl
-c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs
-JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO
-RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30
-3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL
-BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6
-b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ
-KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS
-wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e
-aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s=
+MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
+MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx
+MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
+BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50
+ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco
+LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg
+zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd
+9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw
+CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy
+em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G
+CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6
+hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh
+y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8
 -----END CERTIFICATE-----
diff --git a/src/csharp/ext/grpc_csharp_ext.c b/src/csharp/ext/grpc_csharp_ext.c
index 679ca43d74913c570a1b1c58988aae75af092b04..183931936e764f66a2b1ad3ca81651dd0b2cc723 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -785,9 +785,10 @@ grpcsharp_call_send_initial_metadata(grpc_call *call,
                                NULL);
 }
 
-GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_set_credentials(grpc_call *call,
-                                                            grpc_credentials *creds) {
-	return grpc_call_set_credentials(call, creds);
+GPR_EXPORT grpc_call_error GPR_CALLTYPE grpcsharp_call_set_credentials(
+    grpc_call *call,
+    grpc_call_credentials *creds) {
+  return grpc_call_set_credentials(call, creds);
 }
 
 /* Server */
@@ -834,7 +835,7 @@ grpcsharp_server_request_call(grpc_server *server, grpc_completion_queue *cq,
 
 /* Security */
 
-GPR_EXPORT grpc_credentials *GPR_CALLTYPE
+GPR_EXPORT grpc_channel_credentials *GPR_CALLTYPE
 grpcsharp_ssl_credentials_create(const char *pem_root_certs,
                                  const char *key_cert_pair_cert_chain,
                                  const char *key_cert_pair_private_key) {
@@ -850,12 +851,19 @@ grpcsharp_ssl_credentials_create(const char *pem_root_certs,
   }
 }
 
-GPR_EXPORT void GPR_CALLTYPE grpcsharp_credentials_release(grpc_credentials *creds) {
-  grpc_credentials_release(creds);
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_channel_credentials_release(
+    grpc_channel_credentials *creds) {
+  grpc_channel_credentials_release(creds);
+}
+
+GPR_EXPORT void GPR_CALLTYPE grpcsharp_call_credentials_release(
+    grpc_call_credentials *creds) {
+  grpc_call_credentials_release(creds);
 }
 
 GPR_EXPORT grpc_channel *GPR_CALLTYPE
-grpcsharp_secure_channel_create(grpc_credentials *creds, const char *target,
+grpcsharp_secure_channel_create(grpc_channel_credentials *creds,
+                                const char *target,
                                 const grpc_channel_args *args) {
   return grpc_secure_channel_create(creds, target, args, NULL);
 }
@@ -897,10 +905,16 @@ grpcsharp_server_add_secure_http2_port(grpc_server *server, const char *addr,
   return grpc_server_add_secure_http2_port(server, addr, creds);
 }
 
-GPR_EXPORT grpc_credentials *GPR_CALLTYPE grpcsharp_composite_credentials_create(
-  grpc_credentials *creds1,
-  grpc_credentials *creds2) {
-  return grpc_composite_credentials_create(creds1, creds2, NULL);
+GPR_EXPORT grpc_channel_credentials *GPR_CALLTYPE grpcsharp_composite_channel_credentials_create(
+  grpc_channel_credentials *channel_creds,
+  grpc_call_credentials *call_creds) {
+  return grpc_composite_channel_credentials_create(channel_creds, call_creds, NULL);
+}
+
+GPR_EXPORT grpc_call_credentials *GPR_CALLTYPE grpcsharp_composite_call_credentials_create(
+  grpc_call_credentials *creds1,
+  grpc_call_credentials *creds2) {
+  return grpc_composite_call_credentials_create(creds1, creds2, NULL);
 }
 
 /* Metadata credentials plugin */
@@ -929,7 +943,7 @@ static void grpcsharp_metadata_credentials_destroy_handler(void *state) {
   interceptor(state, NULL, NULL, NULL, 1);
 }
 
-GPR_EXPORT grpc_credentials *GPR_CALLTYPE grpcsharp_metadata_credentials_create_from_plugin(
+GPR_EXPORT grpc_call_credentials *GPR_CALLTYPE grpcsharp_metadata_credentials_create_from_plugin(
   grpcsharp_metadata_interceptor_func metadata_interceptor) {
   grpc_metadata_credentials_plugin plugin;
   plugin.get_metadata = grpcsharp_get_metadata_handler;
diff --git a/src/node/ext/call.cc b/src/node/ext/call.cc
index fe11905109a9463e416d9bd3bf5e28ac0e075168..a98ae85427f53d0c3809661a881149d482e47154 100644
--- a/src/node/ext/call.cc
+++ b/src/node/ext/call.cc
@@ -757,7 +757,7 @@ NAN_METHOD(Call::SetCredentials) {
   Call *call = ObjectWrap::Unwrap<Call>(info.This());
   CallCredentials *creds_object = ObjectWrap::Unwrap<CallCredentials>(
       Nan::To<Object>(info[0]).ToLocalChecked());
-  grpc_credentials *creds = creds_object->GetWrappedCredentials();
+  grpc_call_credentials *creds = creds_object->GetWrappedCredentials();
   grpc_call_error error = GRPC_CALL_ERROR;
   if (creds) {
     error = grpc_call_set_credentials(call->wrapped_call, creds);
diff --git a/src/node/ext/call_credentials.cc b/src/node/ext/call_credentials.cc
index ff16a1f1221f99266a934f3499934eb52588ef3f..9c5d9d291b7492fbef83ff99fa518e38be19fd55 100644
--- a/src/node/ext/call_credentials.cc
+++ b/src/node/ext/call_credentials.cc
@@ -64,11 +64,11 @@ using v8::Value;
 Nan::Callback *CallCredentials::constructor;
 Persistent<FunctionTemplate> CallCredentials::fun_tpl;
 
-CallCredentials::CallCredentials(grpc_credentials *credentials)
+CallCredentials::CallCredentials(grpc_call_credentials *credentials)
     : wrapped_credentials(credentials) {}
 
 CallCredentials::~CallCredentials() {
-  grpc_credentials_release(wrapped_credentials);
+  grpc_call_credentials_release(wrapped_credentials);
 }
 
 void CallCredentials::Init(Local<Object> exports) {
@@ -91,7 +91,7 @@ bool CallCredentials::HasInstance(Local<Value> val) {
   return Nan::New(fun_tpl)->HasInstance(val);
 }
 
-Local<Value> CallCredentials::WrapStruct(grpc_credentials *credentials) {
+Local<Value> CallCredentials::WrapStruct(grpc_call_credentials *credentials) {
   EscapableHandleScope scope;
   const int argc = 1;
   if (credentials == NULL) {
@@ -108,7 +108,7 @@ Local<Value> CallCredentials::WrapStruct(grpc_credentials *credentials) {
   }
 }
 
-grpc_credentials *CallCredentials::GetWrappedCredentials() {
+grpc_call_credentials *CallCredentials::GetWrappedCredentials() {
   return wrapped_credentials;
 }
 
@@ -119,8 +119,8 @@ NAN_METHOD(CallCredentials::New) {
           "CallCredentials can only be created with the provided functions");
     }
     Local<External> ext = info[0].As<External>();
-    grpc_credentials *creds_value =
-        reinterpret_cast<grpc_credentials *>(ext->Value());
+    grpc_call_credentials *creds_value =
+        reinterpret_cast<grpc_call_credentials *>(ext->Value());
     CallCredentials *credentials = new CallCredentials(creds_value);
     credentials->Wrap(info.This());
     info.GetReturnValue().Set(info.This());
@@ -144,7 +144,7 @@ NAN_METHOD(CallCredentials::Compose) {
   CallCredentials *self = ObjectWrap::Unwrap<CallCredentials>(info.This());
   CallCredentials *other = ObjectWrap::Unwrap<CallCredentials>(
       Nan::To<Object>(info[0]).ToLocalChecked());
-  grpc_credentials *creds = grpc_composite_credentials_create(
+  grpc_call_credentials *creds = grpc_composite_call_credentials_create(
       self->wrapped_credentials, other->wrapped_credentials, NULL);
   info.GetReturnValue().Set(WrapStruct(creds));
 }
@@ -162,8 +162,8 @@ NAN_METHOD(CallCredentials::CreateFromPlugin) {
   plugin.get_metadata = plugin_get_metadata;
   plugin.destroy = plugin_destroy_state;
   plugin.state = reinterpret_cast<void*>(state);
-  grpc_credentials *creds = grpc_metadata_credentials_create_from_plugin(plugin,
-                                                                         NULL);
+  grpc_call_credentials *creds = grpc_metadata_credentials_create_from_plugin(
+      plugin, NULL);
   info.GetReturnValue().Set(WrapStruct(creds));
 }
 
diff --git a/src/node/ext/call_credentials.h b/src/node/ext/call_credentials.h
index 618292d19e8b9b040f529e22b186b49da3fa3b7f..1cd8d8dd5d52451b6afa31d9e4d0de24a7884079 100644
--- a/src/node/ext/call_credentials.h
+++ b/src/node/ext/call_credentials.h
@@ -45,14 +45,14 @@ class CallCredentials : public Nan::ObjectWrap {
  public:
   static void Init(v8::Local<v8::Object> exports);
   static bool HasInstance(v8::Local<v8::Value> val);
-  /* Wrap a grpc_credentials struct in a javascript object */
-  static v8::Local<v8::Value> WrapStruct(grpc_credentials *credentials);
+  /* Wrap a grpc_call_credentials struct in a javascript object */
+  static v8::Local<v8::Value> WrapStruct(grpc_call_credentials *credentials);
 
-  /* Returns the grpc_credentials struct that this object wraps */
-  grpc_credentials *GetWrappedCredentials();
+  /* Returns the grpc_call_credentials struct that this object wraps */
+  grpc_call_credentials *GetWrappedCredentials();
 
  private:
-  explicit CallCredentials(grpc_credentials *credentials);
+  explicit CallCredentials(grpc_call_credentials *credentials);
   ~CallCredentials();
 
   // Prevent copying
@@ -68,7 +68,7 @@ class CallCredentials : public Nan::ObjectWrap {
   // Used for typechecking instances of this javascript class
   static Nan::Persistent<v8::FunctionTemplate> fun_tpl;
 
-  grpc_credentials *wrapped_credentials;
+  grpc_call_credentials *wrapped_credentials;
 };
 
 /* Auth metadata plugin functionality */
diff --git a/src/node/ext/channel.cc b/src/node/ext/channel.cc
index 584a0cf8abfc8e81eaa480ae487daa096daea58e..00fcca6dc8417ca0f0a882be7412994e24ccb8d3 100644
--- a/src/node/ext/channel.cc
+++ b/src/node/ext/channel.cc
@@ -82,7 +82,7 @@ bool ParseChannelArgs(Local<Value> args_val,
     return false;
   }
   grpc_channel_args *channel_args = reinterpret_cast<grpc_channel_args*>(
-      malloc(sizeof(channel_args)));
+      malloc(sizeof(grpc_channel_args)));
   *channel_args_ptr = channel_args;
   Local<Object> args_hash = Nan::To<Object>(args_val).ToLocalChecked();
   Local<Array> keys = Nan::GetOwnPropertyNames(args_hash).ToLocalChecked();
@@ -177,7 +177,7 @@ NAN_METHOD(Channel::New) {
     grpc_channel *wrapped_channel;
     // Owned by the Channel object
     Utf8String host(info[0]);
-    grpc_credentials *creds;
+    grpc_channel_credentials *creds;
     if (!ChannelCredentials::HasInstance(info[1])) {
       return Nan::ThrowTypeError(
           "Channel's second argument must be a ChannelCredentials");
diff --git a/src/node/ext/channel_credentials.cc b/src/node/ext/channel_credentials.cc
index 7ca3b9816cfce9578e33d86b708e7f45846fe8d2..b77ff80af275f22f5b1c9f5966964f0f3455aa67 100644
--- a/src/node/ext/channel_credentials.cc
+++ b/src/node/ext/channel_credentials.cc
@@ -65,11 +65,11 @@ using v8::Value;
 Nan::Callback *ChannelCredentials::constructor;
 Persistent<FunctionTemplate> ChannelCredentials::fun_tpl;
 
-ChannelCredentials::ChannelCredentials(grpc_credentials *credentials)
+ChannelCredentials::ChannelCredentials(grpc_channel_credentials *credentials)
     : wrapped_credentials(credentials) {}
 
 ChannelCredentials::~ChannelCredentials() {
-  grpc_credentials_release(wrapped_credentials);
+  grpc_channel_credentials_release(wrapped_credentials);
 }
 
 void ChannelCredentials::Init(Local<Object> exports) {
@@ -95,7 +95,8 @@ bool ChannelCredentials::HasInstance(Local<Value> val) {
   return Nan::New(fun_tpl)->HasInstance(val);
 }
 
-Local<Value> ChannelCredentials::WrapStruct(grpc_credentials *credentials) {
+Local<Value> ChannelCredentials::WrapStruct(
+    grpc_channel_credentials *credentials) {
   EscapableHandleScope scope;
   const int argc = 1;
   Local<Value> argv[argc] = {
@@ -109,7 +110,7 @@ Local<Value> ChannelCredentials::WrapStruct(grpc_credentials *credentials) {
   }
 }
 
-grpc_credentials *ChannelCredentials::GetWrappedCredentials() {
+grpc_channel_credentials *ChannelCredentials::GetWrappedCredentials() {
   return wrapped_credentials;
 }
 
@@ -120,8 +121,8 @@ NAN_METHOD(ChannelCredentials::New) {
           "ChannelCredentials can only be created with the provided functions");
     }
     Local<External> ext = info[0].As<External>();
-    grpc_credentials *creds_value =
-        reinterpret_cast<grpc_credentials *>(ext->Value());
+    grpc_channel_credentials *creds_value =
+        reinterpret_cast<grpc_channel_credentials *>(ext->Value());
     ChannelCredentials *credentials = new ChannelCredentials(creds_value);
     credentials->Wrap(info.This());
     info.GetReturnValue().Set(info.This());
@@ -153,7 +154,7 @@ NAN_METHOD(ChannelCredentials::CreateSsl) {
     return Nan::ThrowTypeError(
         "createSSl's third argument must be a Buffer if provided");
   }
-  grpc_credentials *creds = grpc_ssl_credentials_create(
+  grpc_channel_credentials *creds = grpc_ssl_credentials_create(
       root_certs, key_cert_pair.private_key == NULL ? NULL : &key_cert_pair,
       NULL);
   if (creds == NULL) {
@@ -180,7 +181,7 @@ NAN_METHOD(ChannelCredentials::Compose) {
   }
   CallCredentials *other = ObjectWrap::Unwrap<CallCredentials>(
       Nan::To<Object>(info[0]).ToLocalChecked());
-  grpc_credentials *creds = grpc_composite_credentials_create(
+  grpc_channel_credentials *creds = grpc_composite_channel_credentials_create(
       self->wrapped_credentials, other->GetWrappedCredentials(), NULL);
   if (creds == NULL) {
     info.GetReturnValue().SetNull();
diff --git a/src/node/ext/channel_credentials.h b/src/node/ext/channel_credentials.h
index 31ea0987bc659b7330b7bc851e9f3a0df1fbac68..89b115267f33e806ff8bb0d7154f152ba62773ad 100644
--- a/src/node/ext/channel_credentials.h
+++ b/src/node/ext/channel_credentials.h
@@ -42,19 +42,19 @@
 namespace grpc {
 namespace node {
 
-/* Wrapper class for grpc_credentials structs */
+/* Wrapper class for grpc_channel_credentials structs */
 class ChannelCredentials : public Nan::ObjectWrap {
  public:
   static void Init(v8::Local<v8::Object> exports);
   static bool HasInstance(v8::Local<v8::Value> val);
-  /* Wrap a grpc_credentials struct in a javascript object */
-  static v8::Local<v8::Value> WrapStruct(grpc_credentials *credentials);
+  /* Wrap a grpc_channel_credentials struct in a javascript object */
+  static v8::Local<v8::Value> WrapStruct(grpc_channel_credentials *credentials);
 
-  /* Returns the grpc_credentials struct that this object wraps */
-  grpc_credentials *GetWrappedCredentials();
+  /* Returns the grpc_channel_credentials struct that this object wraps */
+  grpc_channel_credentials *GetWrappedCredentials();
 
  private:
-  explicit ChannelCredentials(grpc_credentials *credentials);
+  explicit ChannelCredentials(grpc_channel_credentials *credentials);
   ~ChannelCredentials();
 
   // Prevent copying
@@ -70,7 +70,7 @@ class ChannelCredentials : public Nan::ObjectWrap {
   // Used for typechecking instances of this javascript class
   static Nan::Persistent<v8::FunctionTemplate> fun_tpl;
 
-  grpc_credentials *wrapped_credentials;
+  grpc_channel_credentials *wrapped_credentials;
 };
 
 }  // namespace node
diff --git a/src/node/src/client.js b/src/node/src/client.js
index 3cdd55075242c750df019ff1936533d294cecd5e..d57826781d391d6872e6f00b757ee380ffa8a134 100644
--- a/src/node/src/client.js
+++ b/src/node/src/client.js
@@ -612,7 +612,15 @@ exports.makeClientConstructor = function(methods, serviceName) {
     if (!options) {
       options = {};
     }
-    options['grpc.primary_user_agent'] = 'grpc-node/' + version;
+    /* Append the grpc-node user agent string after the application user agent
+     * string, and put the combination at the beginning of the user agent string
+     */
+    if (options['grpc.primary_user_agent']) {
+      options['grpc.primary_user_agent'] += ' ';
+    } else {
+      options['grpc.primary_user_agent'] = '';
+    }
+    options['grpc.primary_user_agent'] += 'grpc-node/' + version;
     /* Private fields use $ as a prefix instead of _ because it is an invalid
      * prefix of a method name */
     this.$channel = new grpc.Channel(address, credentials, options);
diff --git a/src/node/test/credentials_test.js b/src/node/test/credentials_test.js
index 3e01b62cf49fd067c651b01388d84b7563084192..647f648ca93eb08332b58e879589a22d9160a5c0 100644
--- a/src/node/test/credentials_test.js
+++ b/src/node/test/credentials_test.js
@@ -71,7 +71,7 @@ var fakeSuccessfulGoogleCredentials = {
 var fakeFailingGoogleCredentials = {
   getRequestMetadata: function(service_url, callback) {
     setTimeout(function() {
-      callback(new Error('Authorization failure'));
+      callback(new Error('Authentication failure'));
     }, 0);
   }
 };
@@ -218,6 +218,25 @@ describe('client credentials', function() {
       done();
     });
   });
+  it('Should not add metadata with just SSL credentials', function(done) {
+    // Tests idempotency of credentials composition
+    var metadataUpdater = function(service_url, callback) {
+      var metadata = new grpc.Metadata();
+      metadata.set('plugin_key', 'plugin_value');
+      callback(null, metadata);
+    };
+    var creds = grpc.credentials.createFromMetadataGenerator(metadataUpdater);
+    grpc.credentials.combineChannelCredentials(client_ssl_creds, creds);
+    var client = new Client('localhost:' + port, client_ssl_creds,
+                            client_options);
+    var call = client.unary({}, function(err, data) {
+      assert.ifError(err);
+    });
+    call.on('metadata', function(metadata) {
+      assert.deepEqual(metadata.get('plugin_key'), []);
+      done();
+    });
+  });
   it.skip('should get an error from a Google credential', function(done) {
     var creds = grpc.credentials.createFromGoogleCredential(
         fakeFailingGoogleCredentials);
@@ -227,7 +246,7 @@ describe('client credentials', function() {
                             client_options);
     client.unary({}, function(err, data) {
       assert(err);
-      assert.strictEqual(err.message, 'Authorization failure');
+      assert.strictEqual(err.message, 'Authentication failure');
       done();
     });
   });
diff --git a/src/node/test/data/server1.pem b/src/node/test/data/server1.pem
index 8e582e571f643ca3fb6042a786c709a53f5afcf3..f3d43fcc5beadd98542abdaa32acfb555b807559 100644
--- a/src/node/test/data/server1.pem
+++ b/src/node/test/data/server1.pem
@@ -1,16 +1,16 @@
 -----BEGIN CERTIFICATE-----
-MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET
-MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
-dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5
-MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
-BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl
-c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs
-JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO
-RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30
-3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL
-BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6
-b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ
-KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS
-wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e
-aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s=
+MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
+MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx
+MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
+BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50
+ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco
+LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg
+zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd
+9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw
+CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy
+em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G
+CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6
+hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh
+y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8
 -----END CERTIFICATE-----
diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.h b/src/objective-c/GRPCClient/private/GRPCSecureChannel.h
index 4e0881e5a2a32b3c2a3787743026103e823f3dca..b82b9fe35acd90d4cb38802eca886f5ac8297a16 100644
--- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.h
+++ b/src/objective-c/GRPCClient/private/GRPCSecureChannel.h
@@ -35,7 +35,7 @@
 
 #import "GRPCChannel.h"
 
-struct grpc_credentials;
+struct grpc_channel_credentials;
 
 @interface GRPCSecureChannel : GRPCChannel
 - (instancetype)initWithHost:(NSString *)host;
@@ -50,6 +50,6 @@ struct grpc_credentials;
 
 /** The passed arguments aren't required to be valid beyond the invocation of this initializer. */
 - (instancetype)initWithHost:(NSString *)host
-                 credentials:(struct grpc_credentials *)credentials
+                 credentials:(struct grpc_channel_credentials *)credentials
                         args:(grpc_channel_args *)args NS_DESIGNATED_INITIALIZER;
 @end
diff --git a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
index ce166553300e5f2a5bd9d69c8c4deba91e301943..a573c171e93ec6b1f900d5225a1c42543f300cb6 100644
--- a/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
+++ b/src/objective-c/GRPCClient/private/GRPCSecureChannel.m
@@ -37,7 +37,7 @@
 
 // Returns NULL if the file at path couldn't be read. In that case, if errorPtr isn't NULL,
 // *errorPtr will be an object describing what went wrong.
-static grpc_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) {
+static grpc_channel_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr) {
   // Files in PEM format can have non-ASCII characters in their comments (e.g. for the name of the
   // issuer). Load them as UTF8 and produce an ASCII equivalent.
   NSString *contentInUTF8 = [NSString stringWithContentsOfFile:path
@@ -62,7 +62,7 @@ static grpc_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr)
           pathToCertificates:(NSString *)path
             hostNameOverride:(NSString *)hostNameOverride {
   // Load default SSL certificates once.
-  static grpc_credentials *kDefaultCertificates;
+  static grpc_channel_credentials *kDefaultCertificates;
   static dispatch_once_t loading;
   dispatch_once(&loading, ^{
     NSString *defaultPath = @"gRPCCertificates.bundle/roots"; // .pem
@@ -79,7 +79,9 @@ static grpc_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr)
   });
 
   //TODO(jcanizales): Add NSError** parameter to the initializer.
-  grpc_credentials *certificates = path ? CertificatesAtPath(path, NULL) : kDefaultCertificates;
+  grpc_channel_credentials *certificates = path
+      ? CertificatesAtPath(path, NULL)
+      : kDefaultCertificates;
   if (!certificates) {
     return nil;
   }
@@ -99,7 +101,7 @@ static grpc_credentials *CertificatesAtPath(NSString *path, NSError **errorPtr)
 }
 
 - (instancetype)initWithHost:(NSString *)host
-                 credentials:(grpc_credentials *)credentials
+                 credentials:(grpc_channel_credentials *)credentials
                         args:(grpc_channel_args *)args {
   return (self = [super
               initWithChannel:grpc_secure_channel_create(
diff --git a/src/objective-c/examples/Sample/Podfile b/src/objective-c/examples/Sample/Podfile
index 72308c1619294e04d890374d72fbbf4e3c3f621d..3b2f41256940c4931638bf5b422d03e08adf72f2 100644
--- a/src/objective-c/examples/Sample/Podfile
+++ b/src/objective-c/examples/Sample/Podfile
@@ -1,8 +1,9 @@
 source 'https://github.com/CocoaPods/Specs.git'
 platform :ios, '8.0'
 
+pod 'Protobuf', :path => "../../../../third_party/protobuf"
 pod 'gRPC', :path => "../../../.."
-pod 'RemoteTest', :path => "../../generated_libraries/RemoteTestClient"
+pod 'RemoteTest', :path => "../RemoteTestClient"
 
 target 'Sample' do
 end
diff --git a/src/objective-c/examples/Sample/Sample/ViewController.m b/src/objective-c/examples/Sample/Sample/ViewController.m
index 05bd6fa2dbc5c5ba8be85cfc8e2c7a9c89f39952..3d634a340df6dad79715fc9a91f7d0216262bf71 100644
--- a/src/objective-c/examples/Sample/Sample/ViewController.m
+++ b/src/objective-c/examples/Sample/Sample/ViewController.m
@@ -34,7 +34,7 @@
 #import "ViewController.h"
 
 #import <GRPCClient/GRPCCall.h>
-#import <GRPCClient/GRPCMethodName.h>
+#import <ProtoRPC/ProtoMethod.h>
 #import <RemoteTest/Messages.pbobjc.h>
 #import <RemoteTest/Test.pbrpc.h>
 #import <RxLibrary/GRXWriter+Immediate.h>
@@ -66,14 +66,14 @@
 
   // Same example call using the generic gRPC client library:
 
-  GRPCMethodName *method = [[GRPCMethodName alloc] initWithPackage:@"grpc.testing"
-                                                         interface:@"TestService"
-                                                            method:@"UnaryCall"];
+  ProtoMethod *method = [[ProtoMethod alloc] initWithPackage:@"grpc.testing"
+                                                     service:@"TestService"
+                                                      method:@"UnaryCall"];
 
-  id<GRXWriter> requestsWriter = [GRXWriter writerWithValue:[request data]];
+  GRXWriter *requestsWriter = [GRXWriter writerWithValue:[request data]];
 
   GRPCCall *call = [[GRPCCall alloc] initWithHost:kRemoteHost
-                                           method:method
+                                             path:method.HTTPPath
                                    requestsWriter:requestsWriter];
 
   id<GRXWriteable> responsesWriteable = [[GRXWriteable alloc] initWithValueHandler:^(NSData *value) {
diff --git a/src/objective-c/generated_libraries/RouteGuideClient/RouteGuide.podspec b/src/objective-c/generated_libraries/RouteGuideClient/RouteGuide.podspec
deleted file mode 100644
index 23ccffe69dacd61f397e99b5b12734b6fb4ee14b..0000000000000000000000000000000000000000
--- a/src/objective-c/generated_libraries/RouteGuideClient/RouteGuide.podspec
+++ /dev/null
@@ -1,31 +0,0 @@
-Pod::Spec.new do |s|
-  s.name     = "RouteGuide"
-  s.version  = "0.0.1"
-  s.license  = "New BSD"
-
-  s.ios.deployment_target = "6.0"
-  s.osx.deployment_target = "10.8"
-
-  # Run protoc with the Objective-C and gRPC plugins to generate protocol messages and gRPC clients.
-  s.prepare_command = <<-CMD
-    BINDIR=../../../../bins/$CONFIG
-    PROTOC=$BINDIR/protobuf/protoc
-    PLUGIN=$BINDIR/grpc_objective_c_plugin
-    $PROTOC --plugin=protoc-gen-grpc=$PLUGIN --objc_out=. --grpc_out=. *.proto
-  CMD
-
-  s.subspec "Messages" do |ms|
-    ms.source_files = "*.pbobjc.{h,m}"
-    ms.header_mappings_dir = "."
-    ms.requires_arc = false
-    ms.dependency "Protobuf", "~> 3.0.0-alpha-3"
-  end
-
-  s.subspec "Services" do |ss|
-    ss.source_files = "*.pbrpc.{h,m}"
-    ss.header_mappings_dir = "."
-    ss.requires_arc = true
-    ss.dependency "gRPC", "~> 0.5"
-    ss.dependency "#{s.name}/Messages"
-  end
-end
diff --git a/src/objective-c/generated_libraries/RouteGuideClient/route_guide.proto b/src/objective-c/generated_libraries/RouteGuideClient/route_guide.proto
deleted file mode 100644
index 19592e2ebdd6fa88fb384a0305a790a8a0d4218e..0000000000000000000000000000000000000000
--- a/src/objective-c/generated_libraries/RouteGuideClient/route_guide.proto
+++ /dev/null
@@ -1,120 +0,0 @@
-// Copyright 2015, Google Inc.
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-syntax = "proto3";
-
-package routeguide;
-
-option objc_class_prefix = "RGD";
-
-// Interface exported by the server.
-service RouteGuide {
-  // A simple RPC.
-  //
-  // Obtains the feature at a given position.
-  rpc GetFeature(Point) returns (Feature) {}
-
-  // A server-to-client streaming RPC.
-  //
-  // Obtains the Features available within the given Rectangle.  Results are
-  // streamed rather than returned at once (e.g. in a response message with a
-  // repeated field), as the rectangle may cover a large area and contain a
-  // huge number of features.
-  rpc ListFeatures(Rectangle) returns (stream Feature) {}
-
-  // A client-to-server streaming RPC.
-  //
-  // Accepts a stream of Points on a route being traversed, returning a
-  // RouteSummary when traversal is completed.
-  rpc RecordRoute(stream Point) returns (RouteSummary) {}
-
-  // A Bidirectional streaming RPC.
-  //
-  // Accepts a stream of RouteNotes sent while a route is being traversed,
-  // while receiving other RouteNotes (e.g. from other users).
-  rpc RouteChat(stream RouteNote) returns (stream RouteNote) {}
-}
-
-// Points are represented as latitude-longitude pairs in the E7 representation
-// (degrees multiplied by 10**7 and rounded to the nearest integer).
-// Latitudes should be in the range +/- 90 degrees and longitude should be in
-// the range +/- 180 degrees (inclusive).
-message Point {
-  int32 latitude = 1;
-  int32 longitude = 2;
-}
-
-// A latitude-longitude rectangle, represented as two diagonally opposite
-// points "lo" and "hi".
-message Rectangle {
-  // One corner of the rectangle.
-  Point lo = 1;
-
-  // The other corner of the rectangle.
-  Point hi = 2;
-}
-
-// A feature names something at a given point.
-//
-// If a feature could not be named, the name is empty.
-message Feature {
-  // The name of the feature.
-  string name = 1;
-
-  // The point where the feature is detected.
-  Point location = 2;
-}
-
-// A RouteNote is a message sent while at a given point.
-message RouteNote {
-  // The location from which the message is sent.
-  Point location = 1;
-
-  // The message to be sent.
-  string message = 2;
-}
-
-// A RouteSummary is received in response to a RecordRoute rpc.
-//
-// It contains the number of individual points received, the number of
-// detected features, and the total distance covered as the cumulative sum of
-// the distance between each point.
-message RouteSummary {
-  // The number of points received.
-  int32 point_count = 1;
-
-  // The number of known features passed while traversing the route.
-  int32 feature_count = 2;
-
-  // The distance covered in metres.
-  int32 distance = 3;
-
-  // The duration of the traversal in seconds.
-  int32 elapsed_time = 4;
-}
diff --git a/src/objective-c/tests/Podfile b/src/objective-c/tests/Podfile
index 2a9b894cf631c8a46b19543e69ae8809ab7b522b..cab608d37fee7df15ad461ffe08a6501f9ea3b3c 100644
--- a/src/objective-c/tests/Podfile
+++ b/src/objective-c/tests/Podfile
@@ -3,8 +3,7 @@ platform :ios, '8.0'
 
 pod 'Protobuf', :path => "../../../third_party/protobuf"
 pod 'gRPC', :path => "../../.."
-pod 'RemoteTest', :path => "../generated_libraries/RemoteTestClient"
-pod 'RouteGuide', :path => "../generated_libraries/RouteGuideClient"
+pod 'RemoteTest', :path => "RemoteTestClient"
 
 link_with 'AllTests',
           'RxLibraryUnitTests',
diff --git a/src/objective-c/generated_libraries/RemoteTestClient/RemoteTest.podspec b/src/objective-c/tests/RemoteTestClient/RemoteTest.podspec
similarity index 100%
rename from src/objective-c/generated_libraries/RemoteTestClient/RemoteTest.podspec
rename to src/objective-c/tests/RemoteTestClient/RemoteTest.podspec
diff --git a/src/objective-c/generated_libraries/RemoteTestClient/empty.proto b/src/objective-c/tests/RemoteTestClient/empty.proto
similarity index 100%
rename from src/objective-c/generated_libraries/RemoteTestClient/empty.proto
rename to src/objective-c/tests/RemoteTestClient/empty.proto
diff --git a/src/objective-c/generated_libraries/RemoteTestClient/messages.proto b/src/objective-c/tests/RemoteTestClient/messages.proto
similarity index 100%
rename from src/objective-c/generated_libraries/RemoteTestClient/messages.proto
rename to src/objective-c/tests/RemoteTestClient/messages.proto
diff --git a/src/objective-c/generated_libraries/RemoteTestClient/test.proto b/src/objective-c/tests/RemoteTestClient/test.proto
similarity index 100%
rename from src/objective-c/generated_libraries/RemoteTestClient/test.proto
rename to src/objective-c/tests/RemoteTestClient/test.proto
diff --git a/src/php/ext/grpc/call_credentials.c b/src/php/ext/grpc/call_credentials.c
new file mode 100644
index 0000000000000000000000000000000000000000..17f167befb09e78e34777f3ce4b1444297f658bf
--- /dev/null
+++ b/src/php/ext/grpc/call_credentials.c
@@ -0,0 +1,138 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "channel_credentials.h"
+#include "call_credentials.h"
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <php.h>
+#include <php_ini.h>
+#include <ext/standard/info.h>
+#include <ext/spl/spl_exceptions.h>
+#include "php_grpc.h"
+
+#include <zend_exceptions.h>
+#include <zend_hash.h>
+
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+
+zend_class_entry *grpc_ce_call_credentials;
+
+/* Frees and destroys an instance of wrapped_grpc_call_credentials */
+void free_wrapped_grpc_call_credentials(void *object TSRMLS_DC) {
+  wrapped_grpc_call_credentials *creds =
+      (wrapped_grpc_call_credentials *)object;
+  if (creds->wrapped != NULL) {
+    grpc_call_credentials_release(creds->wrapped);
+  }
+  efree(creds);
+}
+
+/* Initializes an instance of wrapped_grpc_call_credentials to be
+ * associated with an object of a class specified by class_type */
+zend_object_value create_wrapped_grpc_call_credentials(
+    zend_class_entry *class_type TSRMLS_DC) {
+  zend_object_value retval;
+  wrapped_grpc_call_credentials *intern;
+
+  intern = (wrapped_grpc_call_credentials *)emalloc(
+      sizeof(wrapped_grpc_call_credentials));
+  memset(intern, 0, sizeof(wrapped_grpc_call_credentials));
+
+  zend_object_std_init(&intern->std, class_type TSRMLS_CC);
+  object_properties_init(&intern->std, class_type);
+  retval.handle = zend_objects_store_put(
+      intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
+      free_wrapped_grpc_call_credentials, NULL TSRMLS_CC);
+  retval.handlers = zend_get_std_object_handlers();
+  return retval;
+}
+
+zval *grpc_php_wrap_call_credentials(grpc_call_credentials *wrapped) {
+  zval *credentials_object;
+  MAKE_STD_ZVAL(credentials_object);
+  object_init_ex(credentials_object, grpc_ce_call_credentials);
+  wrapped_grpc_call_credentials *credentials =
+      (wrapped_grpc_call_credentials *)zend_object_store_get_object(
+          credentials_object TSRMLS_CC);
+  credentials->wrapped = wrapped;
+  return credentials_object;
+}
+
+/**
+ * Create composite credentials from two existing credentials.
+ * @param CallCredentials cred1 The first credential
+ * @param CallCredentials cred2 The second credential
+ * @return CallCredentials The new composite credentials object
+ */
+PHP_METHOD(CallCredentials, createComposite) {
+  zval *cred1_obj;
+  zval *cred2_obj;
+
+  /* "OO" == 3 Objects */
+  if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &cred1_obj,
+                            grpc_ce_call_credentials, &cred2_obj,
+                            grpc_ce_call_credentials) == FAILURE) {
+    zend_throw_exception(spl_ce_InvalidArgumentException,
+                         "createComposite expects 2 CallCredentials",
+                         1 TSRMLS_CC);
+    return;
+  }
+  wrapped_grpc_call_credentials *cred1 =
+      (wrapped_grpc_call_credentials *)zend_object_store_get_object(
+          cred1_obj TSRMLS_CC);
+  wrapped_grpc_call_credentials *cred2 =
+      (wrapped_grpc_call_credentials *)zend_object_store_get_object(
+          cred2_obj TSRMLS_CC);
+  grpc_call_credentials *creds =
+      grpc_composite_call_credentials_create(cred1->wrapped, cred2->wrapped,
+                                             NULL);
+  zval *creds_object = grpc_php_wrap_call_credentials(creds);
+  RETURN_DESTROY_ZVAL(creds_object);
+}
+
+static zend_function_entry call_credentials_methods[] = {
+  PHP_ME(CallCredentials, createComposite, NULL,
+         ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+  PHP_FE_END};
+
+void grpc_init_call_credentials(TSRMLS_D) {
+  zend_class_entry ce;
+  INIT_CLASS_ENTRY(ce, "Grpc\\CallCredentials", call_credentials_methods);
+  ce.create_object = create_wrapped_grpc_call_credentials;
+  grpc_ce_call_credentials = zend_register_internal_class(&ce TSRMLS_CC);
+}
diff --git a/src/php/ext/grpc/credentials.h b/src/php/ext/grpc/call_credentials.h
similarity index 76%
rename from src/php/ext/grpc/credentials.h
rename to src/php/ext/grpc/call_credentials.h
index 86d7ae5b144c983726a861674bbb7a0414f00e31..8f35ac68bc1b7e10543e712e2e5c8d6faf8f3eb5 100755
--- a/src/php/ext/grpc/credentials.h
+++ b/src/php/ext/grpc/call_credentials.h
@@ -31,8 +31,8 @@
  *
  */
 
-#ifndef NET_GRPC_PHP_GRPC_CREDENTIALS_H_
-#define NET_GRPC_PHP_GRPC_CREDENTIALS_H_
+#ifndef NET_GRPC_PHP_GRPC_CALL_CREDENTIALS_H_
+#define NET_GRPC_PHP_GRPC_CALL_CREDENTIALS_H_
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -46,18 +46,18 @@
 #include "grpc/grpc.h"
 #include "grpc/grpc_security.h"
 
-/* Class entry for the Credentials PHP class */
-extern zend_class_entry *grpc_ce_credentials;
+/* Class entry for the CallCredentials PHP class */
+extern zend_class_entry *grpc_ce_call_credentials;
 
-/* Wrapper struct for grpc_credentials that can be associated with a PHP
- * object */
-typedef struct wrapped_grpc_credentials {
+/* Wrapper struct for grpc_call_credentials that can be associated
+ * with a PHP object */
+typedef struct wrapped_grpc_call_credentials {
   zend_object std;
 
-  grpc_credentials *wrapped;
-} wrapped_grpc_credentials;
+  grpc_call_credentials *wrapped;
+} wrapped_grpc_call_credentials;
 
-/* Initializes the Credentials PHP class */
-void grpc_init_credentials(TSRMLS_D);
+/* Initializes the CallCredentials PHP class */
+void grpc_init_call_credentials(TSRMLS_D);
 
-#endif /* NET_GRPC_PHP_GRPC_CREDENTIALS_H_ */
+#endif /* NET_GRPC_PHP_GRPC_CALL_CREDENTIALS_H_ */
diff --git a/src/php/ext/grpc/channel.c b/src/php/ext/grpc/channel.c
index a4313b6bd4c0b563d347cd91fa68816815d6b85e..f8c4f0423f2660012ac155ca2f76f5685a5e7a31 100644
--- a/src/php/ext/grpc/channel.c
+++ b/src/php/ext/grpc/channel.c
@@ -52,7 +52,7 @@
 #include <grpc/grpc_security.h>
 
 #include "completion_queue.h"
-#include "credentials.h"
+#include "channel_credentials.h"
 #include "server.h"
 #include "timeval.h"
 
@@ -125,21 +125,22 @@ void php_grpc_read_args_array(zval *args_array, grpc_channel_args *args) {
 
 /**
  * Construct an instance of the Channel class. If the $args array contains a
- * "credentials" key mapping to a Credentials object, a secure channel will be
- * created with those credentials.
+ * "credentials" key mapping to a ChannelCredentials object, a secure channel
+ * will be created with those credentials.
  * @param string $target The hostname to associate with this channel
  * @param array $args The arguments to pass to the Channel (optional)
  */
 PHP_METHOD(Channel, __construct) {
   wrapped_grpc_channel *channel =
-      (wrapped_grpc_channel *)zend_object_store_get_object(getThis() TSRMLS_CC);
+      (wrapped_grpc_channel *)zend_object_store_get_object(
+          getThis() TSRMLS_CC);
   char *target;
   int target_length;
   zval *args_array = NULL;
   grpc_channel_args args;
   HashTable *array_hash;
   zval **creds_obj = NULL;
-  wrapped_grpc_credentials *creds = NULL;
+  wrapped_grpc_channel_credentials *creds = NULL;
   /* "s|a" == 1 string, 1 optional array */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|a", &target,
                             &target_length, &args_array) == FAILURE) {
@@ -153,13 +154,14 @@ PHP_METHOD(Channel, __construct) {
     array_hash = Z_ARRVAL_P(args_array);
     if (zend_hash_find(array_hash, "credentials", sizeof("credentials"),
                        (void **)&creds_obj) == SUCCESS) {
-      if (zend_get_class_entry(*creds_obj TSRMLS_CC) != grpc_ce_credentials) {
+      if (zend_get_class_entry(*creds_obj TSRMLS_CC) !=
+          grpc_ce_channel_credentials) {
         zend_throw_exception(spl_ce_InvalidArgumentException,
-                             "credentials must be a Credentials object",
+                             "credentials must be a ChannelCredentials object",
                              1 TSRMLS_CC);
         return;
       }
-      creds = (wrapped_grpc_credentials *)zend_object_store_get_object(
+      creds = (wrapped_grpc_channel_credentials *)zend_object_store_get_object(
           *creds_obj TSRMLS_CC);
       zend_hash_del(array_hash, "credentials", 12);
     }
diff --git a/src/php/ext/grpc/credentials.c b/src/php/ext/grpc/channel_credentials.c
similarity index 55%
rename from src/php/ext/grpc/credentials.c
rename to src/php/ext/grpc/channel_credentials.c
index e413070b4531cc2e0218d4796d014e88b8d89c6a..df4a5d516246829bd02ffdaf6cf49f53039361c3 100644
--- a/src/php/ext/grpc/credentials.c
+++ b/src/php/ext/grpc/channel_credentials.c
@@ -31,7 +31,8 @@
  *
  */
 
-#include "credentials.h"
+#include "channel_credentials.h"
+#include "call_credentials.h"
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -49,55 +50,56 @@
 #include <grpc/grpc.h>
 #include <grpc/grpc_security.h>
 
-zend_class_entry *grpc_ce_credentials;
+zend_class_entry *grpc_ce_channel_credentials;
 
-/* Frees and destroys an instance of wrapped_grpc_credentials */
-void free_wrapped_grpc_credentials(void *object TSRMLS_DC) {
-  wrapped_grpc_credentials *creds = (wrapped_grpc_credentials *)object;
+/* Frees and destroys an instance of wrapped_grpc_channel_credentials */
+void free_wrapped_grpc_channel_credentials(void *object TSRMLS_DC) {
+  wrapped_grpc_channel_credentials *creds =
+      (wrapped_grpc_channel_credentials *)object;
   if (creds->wrapped != NULL) {
-    grpc_credentials_release(creds->wrapped);
+    grpc_channel_credentials_release(creds->wrapped);
   }
   efree(creds);
 }
 
-/* Initializes an instance of wrapped_grpc_credentials to be associated with an
- * object of a class specified by class_type */
-zend_object_value create_wrapped_grpc_credentials(zend_class_entry *class_type
-                                                      TSRMLS_DC) {
+/* Initializes an instance of wrapped_grpc_channel_credentials to be
+ * associated with an object of a class specified by class_type */
+zend_object_value create_wrapped_grpc_channel_credentials(
+    zend_class_entry *class_type TSRMLS_DC) {
   zend_object_value retval;
-  wrapped_grpc_credentials *intern;
+  wrapped_grpc_channel_credentials *intern;
 
-  intern =
-      (wrapped_grpc_credentials *)emalloc(sizeof(wrapped_grpc_credentials));
-  memset(intern, 0, sizeof(wrapped_grpc_credentials));
+  intern = (wrapped_grpc_channel_credentials *)emalloc(
+      sizeof(wrapped_grpc_channel_credentials));
+  memset(intern, 0, sizeof(wrapped_grpc_channel_credentials));
 
   zend_object_std_init(&intern->std, class_type TSRMLS_CC);
   object_properties_init(&intern->std, class_type);
   retval.handle = zend_objects_store_put(
       intern, (zend_objects_store_dtor_t)zend_objects_destroy_object,
-      free_wrapped_grpc_credentials, NULL TSRMLS_CC);
+      free_wrapped_grpc_channel_credentials, NULL TSRMLS_CC);
   retval.handlers = zend_get_std_object_handlers();
   return retval;
 }
 
-zval *grpc_php_wrap_credentials(grpc_credentials *wrapped) {
+zval *grpc_php_wrap_channel_credentials(grpc_channel_credentials *wrapped) {
   zval *credentials_object;
   MAKE_STD_ZVAL(credentials_object);
-  object_init_ex(credentials_object, grpc_ce_credentials);
-  wrapped_grpc_credentials *credentials =
-      (wrapped_grpc_credentials *)zend_object_store_get_object(
+  object_init_ex(credentials_object, grpc_ce_channel_credentials);
+  wrapped_grpc_channel_credentials *credentials =
+      (wrapped_grpc_channel_credentials *)zend_object_store_get_object(
           credentials_object TSRMLS_CC);
   credentials->wrapped = wrapped;
   return credentials_object;
 }
 
 /**
- * Create a default credentials object.
- * @return Credentials The new default credentials object
+ * Create a default channel credentials object.
+ * @return ChannelCredentials The new default channel credentials object
  */
-PHP_METHOD(Credentials, createDefault) {
-  grpc_credentials *creds = grpc_google_default_credentials_create();
-  zval *creds_object = grpc_php_wrap_credentials(creds);
+PHP_METHOD(ChannelCredentials, createDefault) {
+  grpc_channel_credentials *creds = grpc_google_default_credentials_create();
+  zval *creds_object = grpc_php_wrap_channel_credentials(creds);
   RETURN_DESTROY_ZVAL(creds_object);
 }
 
@@ -108,9 +110,9 @@ PHP_METHOD(Credentials, createDefault) {
  *     (optional)
  * @param string pem_cert_chain PEM encoding of the client's certificate chain
  *     (optional)
- * @return Credentials The new SSL credentials object
+ * @return ChannelCredentials The new SSL credentials object
  */
-PHP_METHOD(Credentials, createSsl) {
+PHP_METHOD(ChannelCredentials, createSsl) {
   char *pem_root_certs = NULL;
   grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
 
@@ -121,71 +123,65 @@ PHP_METHOD(Credentials, createSsl) {
   /* "|s!s!s! == 3 optional nullable strings */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!s!s!",
                             &pem_root_certs, &root_certs_length,
-                            &pem_key_cert_pair.private_key, &private_key_length,
+                            &pem_key_cert_pair.private_key,
+                            &private_key_length,
                             &pem_key_cert_pair.cert_chain,
                             &cert_chain_length) == FAILURE) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
                          "createSsl expects 3 optional strings", 1 TSRMLS_CC);
     return;
   }
-  grpc_credentials *creds = grpc_ssl_credentials_create(
+  grpc_channel_credentials *creds = grpc_ssl_credentials_create(
       pem_root_certs,
       pem_key_cert_pair.private_key == NULL ? NULL : &pem_key_cert_pair, NULL);
-  zval *creds_object = grpc_php_wrap_credentials(creds);
+  zval *creds_object = grpc_php_wrap_channel_credentials(creds);
   RETURN_DESTROY_ZVAL(creds_object);
 }
 
 /**
  * Create composite credentials from two existing credentials.
- * @param Credentials cred1 The first credential
- * @param Credentials cred2 The second credential
- * @return Credentials The new composite credentials object
+ * @param ChannelCredentials cred1 The first credential
+ * @param CallCredentials cred2 The second credential
+ * @return ChannelCredentials The new composite credentials object
  */
-PHP_METHOD(Credentials, createComposite) {
+PHP_METHOD(ChannelCredentials, createComposite) {
   zval *cred1_obj;
   zval *cred2_obj;
 
   /* "OO" == 3 Objects */
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &cred1_obj,
-                            grpc_ce_credentials, &cred2_obj,
-                            grpc_ce_credentials) == FAILURE) {
+                            grpc_ce_channel_credentials, &cred2_obj,
+                            grpc_ce_call_credentials) == FAILURE) {
     zend_throw_exception(spl_ce_InvalidArgumentException,
                          "createComposite expects 2 Credentials", 1 TSRMLS_CC);
     return;
   }
-  wrapped_grpc_credentials *cred1 =
-      (wrapped_grpc_credentials *)zend_object_store_get_object(
+  wrapped_grpc_channel_credentials *cred1 =
+      (wrapped_grpc_channel_credentials *)zend_object_store_get_object(
           cred1_obj TSRMLS_CC);
-  wrapped_grpc_credentials *cred2 =
-      (wrapped_grpc_credentials *)zend_object_store_get_object(
+  wrapped_grpc_call_credentials *cred2 =
+      (wrapped_grpc_call_credentials *)zend_object_store_get_object(
           cred2_obj TSRMLS_CC);
-  grpc_credentials *creds =
-      grpc_composite_credentials_create(cred1->wrapped, cred2->wrapped, NULL);
-  zval *creds_object = grpc_php_wrap_credentials(creds);
+  grpc_channel_credentials *creds =
+      grpc_composite_channel_credentials_create(cred1->wrapped, cred2->wrapped,
+                                                NULL);
+  zval *creds_object = grpc_php_wrap_channel_credentials(creds);
   RETURN_DESTROY_ZVAL(creds_object);
 }
 
-/**
- * Create Google Compute Engine credentials
- * @return Credentials The new GCE credentials object
- */
-PHP_METHOD(Credentials, createGce) {
-  grpc_credentials *creds = grpc_google_compute_engine_credentials_create(NULL);
-  zval *creds_object = grpc_php_wrap_credentials(creds);
-  RETURN_DESTROY_ZVAL(creds_object);
-}
-
-static zend_function_entry credentials_methods[] = {
-    PHP_ME(Credentials, createDefault, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-    PHP_ME(Credentials, createSsl, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-    PHP_ME(Credentials, createComposite, NULL,
-           ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-    PHP_ME(Credentials, createGce, NULL, ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
-    PHP_FE_END};
+static zend_function_entry channel_credentials_methods[] = {
+  PHP_ME(ChannelCredentials, createDefault, NULL,
+         ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+  PHP_ME(ChannelCredentials, createSsl, NULL,
+         ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+  PHP_ME(ChannelCredentials, createComposite, NULL,
+         ZEND_ACC_PUBLIC | ZEND_ACC_STATIC)
+  PHP_FE_END};
 
-void grpc_init_credentials(TSRMLS_D) {
+void grpc_init_channel_credentials(TSRMLS_D) {
   zend_class_entry ce;
-  INIT_CLASS_ENTRY(ce, "Grpc\\Credentials", credentials_methods);
-  ce.create_object = create_wrapped_grpc_credentials;
-  grpc_ce_credentials = zend_register_internal_class(&ce TSRMLS_CC);
+  INIT_CLASS_ENTRY(ce, "Grpc\\ChannelCredentials",
+                   channel_credentials_methods);
+  ce.create_object = create_wrapped_grpc_channel_credentials;
+  grpc_ce_channel_credentials = zend_register_internal_class(&ce TSRMLS_CC);
 }
diff --git a/src/php/ext/grpc/channel_credentials.h b/src/php/ext/grpc/channel_credentials.h
new file mode 100755
index 0000000000000000000000000000000000000000..d89984ce604076ee41a8a2b97e05391857e15060
--- /dev/null
+++ b/src/php/ext/grpc/channel_credentials.h
@@ -0,0 +1,63 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#ifndef NET_GRPC_PHP_GRPC_CHANNEL_CREDENTIALS_H_
+#define NET_GRPC_PHP_GRPC_CHANNEL_CREDENTIALS_H_
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "php_ini.h"
+#include "ext/standard/info.h"
+#include "php_grpc.h"
+
+#include "grpc/grpc.h"
+#include "grpc/grpc_security.h"
+
+/* Class entry for the ChannelCredentials PHP class */
+extern zend_class_entry *grpc_ce_channel_credentials;
+
+/* Wrapper struct for grpc_channel_credentials that can be associated
+ * with a PHP object */
+typedef struct wrapped_grpc_channel_credentials {
+  zend_object std;
+
+  grpc_channel_credentials *wrapped;
+} wrapped_grpc_channel_credentials;
+
+/* Initializes the ChannelCredentials PHP class */
+void grpc_init_channel_credentials(TSRMLS_D);
+
+#endif /* NET_GRPC_PHP_GRPC_CHANNEL_CREDENTIALS_H_ */
diff --git a/src/php/ext/grpc/config.m4 b/src/php/ext/grpc/config.m4
index 8bacdfbfecac1ea6537d266896ad85947ec4ec09..792868794315323c1b454ceb87b1ad80c93eb81c 100755
--- a/src/php/ext/grpc/config.m4
+++ b/src/php/ext/grpc/config.m4
@@ -71,5 +71,7 @@ if test "$PHP_GRPC" != "no"; then
 
   PHP_SUBST(GRPC_SHARED_LIBADD)
 
-  PHP_NEW_EXTENSION(grpc, byte_buffer.c call.c channel.c completion_queue.c credentials.c timeval.c server.c server_credentials.c php_grpc.c, $ext_shared, , -Wall -Werror -std=c11)
+  PHP_NEW_EXTENSION(grpc, byte_buffer.c call.c call_credentials.c channel.c \
+    channel_credentials.c completion_queue.c timeval.c server.c \
+    server_credentials.c php_grpc.c, $ext_shared, , -Wall -Werror -std=c11)
 fi
diff --git a/src/php/ext/grpc/package.xml b/src/php/ext/grpc/package.xml
index 921cfc6ae68d085120331c0de9db36ff4f2f7d69..a2e3e2826a77441e92947c42f0f2ec0c39063f0c 100644
--- a/src/php/ext/grpc/package.xml
+++ b/src/php/ext/grpc/package.xml
@@ -10,8 +10,8 @@
   <email>grpc-packages@google.com</email>
   <active>yes</active>
  </lead>
- <date>2015-10-07</date>
- <time>13:40:54</time>
+ <date>2015-10-21</date>
+ <time>17:04:32</time>
  <version>
   <release>0.6.1</release>
   <api>0.6.0</api>
@@ -30,16 +30,18 @@
    <file baseinstalldir="/" md5sum="c8de0f819499c48adfc8d7f472c0196b" name="byte_buffer.h" role="src" />
    <file baseinstalldir="/" md5sum="d64c9005993de02abac55664b0b9e0b2" name="call.c" role="src" />
    <file baseinstalldir="/" md5sum="26acbf04c30162c2d2aca4688bb2aec8" name="call.h" role="src" />
-   <file baseinstalldir="/" md5sum="15e56239b32c803f073e8a2b9f96e8c3" name="channel.c" role="src" />
+   <file baseinstalldir="/" md5sum="6fa13d260dfde216f795225644f04e7a" name="call_credentials.c" role="src" />
+   <file baseinstalldir="/" md5sum="e45269975f9a30fd349a90daf6b31aa2" name="call_credentials.h" role="src" />
+   <file baseinstalldir="/" md5sum="0779db3b196c98081b2260ceec22cd4d" name="channel.c" role="src" />
    <file baseinstalldir="/" md5sum="ed4b00c0cf3702b115d0cfa87450dc09" name="channel.h" role="src" />
+   <file baseinstalldir="/" md5sum="1b40f50fa6184ad7d24a961ac76151ff" name="channel_credentials.c" role="src" />
+   <file baseinstalldir="/" md5sum="a86250e03f610ce6c2c7595a84e08821" name="channel_credentials.h" role="src" />
    <file baseinstalldir="/" md5sum="55ab7a42f9dd9bfc7e28a61cfc5fca63" name="completion_queue.c" role="src" />
    <file baseinstalldir="/" md5sum="f10b5bb232d74a6878e829e2e76cdaa2" name="completion_queue.h" role="src" />
-   <file baseinstalldir="/" md5sum="a22f8eac0164761058cc4d9eb2ceb069" name="config.m4" role="src" />
-   <file baseinstalldir="/" md5sum="588752c908f7bc1663f7b8fc922ae661" name="credentials.c" role="src" />
-   <file baseinstalldir="/" md5sum="6988d6e97c19c8f8e3eb92371cf8246b" name="credentials.h" role="src" />
+   <file baseinstalldir="/" md5sum="c7bba7f0f00d1b1483de457d55311382" name="config.m4" role="src" />
    <file baseinstalldir="/" md5sum="38a1bc979d810c36ebc2a52d4b7b5319" name="CREDITS" role="doc" />
    <file baseinstalldir="/" md5sum="3f35b472bbdef5a788cd90617d7d0847" name="LICENSE" role="doc" />
-   <file baseinstalldir="/" md5sum="b77f1f3941aaf7a21090b493e9f26037" name="php_grpc.c" role="src" />
+   <file baseinstalldir="/" md5sum="3131a8af38fe5918e5409016b89d6cdb" name="php_grpc.c" role="src" />
    <file baseinstalldir="/" md5sum="673b07859d9f69232f8a754c56780686" name="php_grpc.h" role="src" />
    <file baseinstalldir="/" md5sum="7533a6d3ea02c78cad23a9651de0825d" name="README.md" role="doc" />
    <file baseinstalldir="/" md5sum="3e4e960454ebb2fc7b78a840493f5315" name="server.c" role="src" />
@@ -122,7 +124,7 @@ Update to wrap gRPC C Core version 0.10.0
     <release>beta</release>
     <api>beta</api>
    </stability>
-   <date>2015-10-07</date>
+   <date>2015-10-21</date>
    <license>BSD</license>
    <notes>
 - fixed undefined constant fatal error when run with apache/nginx #2275
diff --git a/src/php/ext/grpc/php_grpc.c b/src/php/ext/grpc/php_grpc.c
index fcd94a6306230db39d60f2ede6305c950978931c..762c01385c95fae2a894986f953b8c9d07f59526 100644
--- a/src/php/ext/grpc/php_grpc.c
+++ b/src/php/ext/grpc/php_grpc.c
@@ -35,7 +35,8 @@
 #include "channel.h"
 #include "server.h"
 #include "timeval.h"
-#include "credentials.h"
+#include "channel_credentials.h"
+#include "call_credentials.h"
 #include "server_credentials.h"
 #include "completion_queue.h"
 
@@ -233,7 +234,8 @@ PHP_MINIT_FUNCTION(grpc) {
   grpc_init_channel(TSRMLS_C);
   grpc_init_server(TSRMLS_C);
   grpc_init_timeval(TSRMLS_C);
-  grpc_init_credentials(TSRMLS_C);
+  grpc_init_channel_credentials(TSRMLS_C);
+  grpc_init_call_credentials(TSRMLS_C);
   grpc_init_server_credentials(TSRMLS_C);
   grpc_php_init_completion_queue(TSRMLS_C);
   return SUCCESS;
diff --git a/src/php/lib/Grpc/BaseStub.php b/src/php/lib/Grpc/BaseStub.php
index c26be607ffc98bb618fbdfac6e2b9e7cfd2a39c4..aa4de349ea7f60b3f8ae41c8ac292f8b5aa05ef6 100755
--- a/src/php/lib/Grpc/BaseStub.php
+++ b/src/php/lib/Grpc/BaseStub.php
@@ -51,6 +51,7 @@ class BaseStub
      * @param $opts array
      *  - 'update_metadata': (optional) a callback function which takes in a
      * metadata array, and returns an updated metadata array
+     *  - 'grpc.primary_user_agent': (optional) a user-agent string
      */
     public function __construct($hostname, $opts)
     {
@@ -64,7 +65,12 @@ class BaseStub
         }
         $package_config = json_decode(
             file_get_contents(dirname(__FILE__).'/../../composer.json'), true);
-        $opts['grpc.primary_user_agent'] =
+        if (!empty($opts['grpc.primary_user_agent'])) {
+            $opts['grpc.primary_user_agent'] .= ' ';
+        } else {
+            $opts['grpc.primary_user_agent'] = '';
+        }
+        $opts['grpc.primary_user_agent'] .=
             'grpc-php/'.$package_config['version'];
         $this->channel = new Channel($hostname, $opts);
     }
diff --git a/src/php/tests/data/server1.pem b/src/php/tests/data/server1.pem
index 8e582e571f643ca3fb6042a786c709a53f5afcf3..f3d43fcc5beadd98542abdaa32acfb555b807559 100755
--- a/src/php/tests/data/server1.pem
+++ b/src/php/tests/data/server1.pem
@@ -1,16 +1,16 @@
 -----BEGIN CERTIFICATE-----
-MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET
-MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
-dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5
-MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
-BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl
-c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs
-JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO
-RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30
-3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL
-BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6
-b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ
-KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS
-wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e
-aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s=
+MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
+MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx
+MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
+BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50
+ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco
+LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg
+zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd
+9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw
+CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy
+em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G
+CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6
+hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh
+y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8
 -----END CERTIFICATE-----
diff --git a/src/php/tests/interop/interop_client.php b/src/php/tests/interop/interop_client.php
index 3019866561e3fa11f9ec58636b66d2a7b433029e..9aab5c966c728615da4852ecc52db1e5d59c08b3 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -423,10 +423,10 @@ $opts = [];
 
 if ($use_tls) {
     if ($use_test_ca) {
-        $ssl_credentials = Grpc\Credentials::createSsl(
-        file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
+        $ssl_credentials = Grpc\ChannelCredentials::createSsl(
+            file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
     } else {
-        $ssl_credentials = Grpc\Credentials::createSsl();
+        $ssl_credentials = Grpc\ChannelCredentials::createSsl();
     }
     $opts['credentials'] = $ssl_credentials;
     $opts['grpc.ssl_target_name_override'] = $host_override;
diff --git a/src/php/tests/unit_tests/SecureEndToEndTest.php b/src/php/tests/unit_tests/SecureEndToEndTest.php
index e66bde376c7a8d45fe17ca469bce7c1a73610c4c..c388ee5031ba66e66035cbba7cbc3637f6dbabac 100755
--- a/src/php/tests/unit_tests/SecureEndToEndTest.php
+++ b/src/php/tests/unit_tests/SecureEndToEndTest.php
@@ -35,7 +35,7 @@ class SecureEndToEndTest extends PHPUnit_Framework_TestCase
 {
     public function setUp()
     {
-        $credentials = Grpc\Credentials::createSsl(
+        $credentials = Grpc\ChannelCredentials::createSsl(
             file_get_contents(dirname(__FILE__).'/../data/ca.pem'));
         $server_credentials = Grpc\ServerCredentials::createSsl(
             null,
diff --git a/src/python/grpcio/grpc/_adapter/_c/types.c b/src/python/grpcio/grpc/_adapter/_c/types.c
index 8855c32ca6d4e859a3dd9632912fa4fd27af660f..8dedf5902b32d47cf41d9ff5bf97a233d16bfd98 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types.c
+++ b/src/python/grpcio/grpc/_adapter/_c/types.c
@@ -40,7 +40,8 @@
 int pygrpc_module_add_types(PyObject *module) {
   int i;
   PyTypeObject *types[] = {
-      &pygrpc_ClientCredentials_type,
+      &pygrpc_CallCredentials_type,
+      &pygrpc_ChannelCredentials_type,
       &pygrpc_ServerCredentials_type,
       &pygrpc_CompletionQueue_type,
       &pygrpc_Call_type,
diff --git a/src/python/grpcio/grpc/_adapter/_c/types.h b/src/python/grpcio/grpc/_adapter/_c/types.h
index 31fd470d36a967473bd28bd26eae53b4c251bc7e..9ab415d216b41497a5e54ab0c851b6aadfde8b5b 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types.h
+++ b/src/python/grpcio/grpc/_adapter/_c/types.h
@@ -44,27 +44,35 @@
 /* Client-side credentials */
 /*=========================*/
 
-typedef struct ClientCredentials {
+typedef struct ChannelCredentials {
   PyObject_HEAD
-  grpc_credentials *c_creds;
-} ClientCredentials;
-void pygrpc_ClientCredentials_dealloc(ClientCredentials *self);
-ClientCredentials *pygrpc_ClientCredentials_google_default(
+  grpc_channel_credentials *c_creds;
+} ChannelCredentials;
+void pygrpc_ChannelCredentials_dealloc(ChannelCredentials *self);
+ChannelCredentials *pygrpc_ChannelCredentials_google_default(
     PyTypeObject *type, PyObject *ignored);
-ClientCredentials *pygrpc_ClientCredentials_ssl(
+ChannelCredentials *pygrpc_ChannelCredentials_ssl(
     PyTypeObject *type, PyObject *args, PyObject *kwargs);
-ClientCredentials *pygrpc_ClientCredentials_composite(
+ChannelCredentials *pygrpc_ChannelCredentials_composite(
     PyTypeObject *type, PyObject *args, PyObject *kwargs);
-ClientCredentials *pygrpc_ClientCredentials_compute_engine(
+extern PyTypeObject pygrpc_ChannelCredentials_type;
+
+typedef struct CallCredentials {
+  PyObject_HEAD
+  grpc_call_credentials *c_creds;
+} CallCredentials;
+void pygrpc_CallCredentials_dealloc(CallCredentials *self);
+CallCredentials *pygrpc_CallCredentials_composite(
+    PyTypeObject *type, PyObject *args, PyObject *kwargs);
+CallCredentials *pygrpc_CallCredentials_compute_engine(
     PyTypeObject *type, PyObject *ignored);
-ClientCredentials *pygrpc_ClientCredentials_jwt(
+CallCredentials *pygrpc_CallCredentials_jwt(
     PyTypeObject *type, PyObject *args, PyObject *kwargs);
-ClientCredentials *pygrpc_ClientCredentials_refresh_token(
+CallCredentials *pygrpc_CallCredentials_refresh_token(
     PyTypeObject *type, PyObject *args, PyObject *kwargs);
-ClientCredentials *pygrpc_ClientCredentials_iam(
+CallCredentials *pygrpc_CallCredentials_iam(
     PyTypeObject *type, PyObject *args, PyObject *kwargs);
-extern PyTypeObject pygrpc_ClientCredentials_type;
-
+extern PyTypeObject pygrpc_CallCredentials_type;
 
 /*=========================*/
 /* Server-side credentials */
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/call.c b/src/python/grpcio/grpc/_adapter/_c/types/call.c
index 5604aba39d506bbf053a0e27d60ee800d5865fb9..04ec871880086a8a87a9d161c7af98ea99a83d06 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types/call.c
+++ b/src/python/grpcio/grpc/_adapter/_c/types/call.c
@@ -173,12 +173,12 @@ PyObject *pygrpc_Call_peer(Call *self) {
 }
 PyObject *pygrpc_Call_set_credentials(Call *self, PyObject *args,
                                       PyObject *kwargs) {
-  ClientCredentials *creds;
+  CallCredentials *creds;
   grpc_call_error errcode;
   static char *keywords[] = {"creds", NULL};
   if (!PyArg_ParseTupleAndKeywords(
       args, kwargs, "O!:set_credentials", keywords,
-      &pygrpc_ClientCredentials_type, &creds)) {
+      &pygrpc_CallCredentials_type, &creds)) {
     return NULL;
   }
   errcode = grpc_call_set_credentials(self->c_call, creds->c_creds);
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/client_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c
similarity index 65%
rename from src/python/grpcio/grpc/_adapter/_c/types/client_credentials.c
rename to src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c
index 90652b7b475395f0fc24ebcc3e92b90563fb4a41..5a15a6e17dc37105bfe3adf93c145be5b8df507a 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types/client_credentials.c
+++ b/src/python/grpcio/grpc/_adapter/_c/types/call_credentials.c
@@ -39,31 +39,28 @@
 #include <grpc/grpc_security.h>
 
 
-PyMethodDef pygrpc_ClientCredentials_methods[] = {
-    {"google_default", (PyCFunction)pygrpc_ClientCredentials_google_default,
-     METH_CLASS|METH_NOARGS, ""},
-    {"ssl", (PyCFunction)pygrpc_ClientCredentials_ssl,
-     METH_CLASS|METH_KEYWORDS, ""},
-    {"composite", (PyCFunction)pygrpc_ClientCredentials_composite,
+PyMethodDef pygrpc_CallCredentials_methods[] = {
+    {"composite", (PyCFunction)pygrpc_CallCredentials_composite,
      METH_CLASS|METH_KEYWORDS, ""},
-    {"compute_engine", (PyCFunction)pygrpc_ClientCredentials_compute_engine,
+    {"compute_engine", (PyCFunction)pygrpc_CallCredentials_compute_engine,
      METH_CLASS|METH_NOARGS, ""},
-    {"jwt", (PyCFunction)pygrpc_ClientCredentials_jwt,
+    {"jwt", (PyCFunction)pygrpc_CallCredentials_jwt,
      METH_CLASS|METH_KEYWORDS, ""},
-    {"refresh_token", (PyCFunction)pygrpc_ClientCredentials_refresh_token,
+    {"refresh_token", (PyCFunction)pygrpc_CallCredentials_refresh_token,
      METH_CLASS|METH_KEYWORDS, ""},
-    {"iam", (PyCFunction)pygrpc_ClientCredentials_iam,
+    {"iam", (PyCFunction)pygrpc_CallCredentials_iam,
      METH_CLASS|METH_KEYWORDS, ""},
     {NULL}
 };
-const char pygrpc_ClientCredentials_doc[] = "";
-PyTypeObject pygrpc_ClientCredentials_type = {
+
+const char pygrpc_CallCredentials_doc[] = "";
+PyTypeObject pygrpc_CallCredentials_type = {
     PyObject_HEAD_INIT(NULL)
     0,                                        /* ob_size */
-    "ClientCredentials",                      /* tp_name */
-    sizeof(ClientCredentials),                /* tp_basicsize */
+    "CallCredentials",                        /* tp_name */
+    sizeof(CallCredentials),                  /* tp_basicsize */
     0,                                        /* tp_itemsize */
-    (destructor)pygrpc_ClientCredentials_dealloc, /* tp_dealloc */
+    (destructor)pygrpc_CallCredentials_dealloc, /* tp_dealloc */
     0,                                        /* tp_print */
     0,                                        /* tp_getattr */
     0,                                        /* tp_setattr */
@@ -79,14 +76,14 @@ PyTypeObject pygrpc_ClientCredentials_type = {
     0,                                        /* tp_setattro */
     0,                                        /* tp_as_buffer */
     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
-    pygrpc_ClientCredentials_doc,             /* tp_doc */
+    pygrpc_CallCredentials_doc,             /* tp_doc */
     0,                                        /* tp_traverse */
     0,                                        /* tp_clear */
     0,                                        /* tp_richcompare */
     0,                                        /* tp_weaklistoffset */
     0,                                        /* tp_iter */
     0,                                        /* tp_iternext */
-    pygrpc_ClientCredentials_methods,         /* tp_methods */
+    pygrpc_CallCredentials_methods,         /* tp_methods */
     0,                                        /* tp_members */
     0,                                        /* tp_getset */
     0,                                        /* tp_base */
@@ -99,67 +96,26 @@ PyTypeObject pygrpc_ClientCredentials_type = {
     0                                         /* tp_new */
 };
 
-void pygrpc_ClientCredentials_dealloc(ClientCredentials *self) {
-  grpc_credentials_release(self->c_creds);
+void pygrpc_CallCredentials_dealloc(CallCredentials *self) {
+  grpc_call_credentials_release(self->c_creds);
   self->ob_type->tp_free((PyObject *)self);
 }
 
-ClientCredentials *pygrpc_ClientCredentials_google_default(
-    PyTypeObject *type, PyObject *ignored) {
-  ClientCredentials *self = (ClientCredentials *)type->tp_alloc(type, 0);
-  self->c_creds = grpc_google_default_credentials_create();
-  if (!self->c_creds) {
-    Py_DECREF(self);
-    PyErr_SetString(PyExc_RuntimeError,
-                    "couldn't create Google default credentials");
-    return NULL;
-  }
-  return self;
-}
-
-ClientCredentials *pygrpc_ClientCredentials_ssl(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs) {
-  ClientCredentials *self;
-  const char *root_certs;
-  const char *private_key = NULL;
-  const char *cert_chain = NULL;
-  grpc_ssl_pem_key_cert_pair key_cert_pair;
-  static char *keywords[] = {"root_certs", "private_key", "cert_chain", NULL};
-  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|zz:ssl", keywords,
-        &root_certs, &private_key, &cert_chain)) {
-    return NULL;
-  }
-  self = (ClientCredentials *)type->tp_alloc(type, 0);
-  if (private_key && cert_chain) {
-    key_cert_pair.private_key = private_key;
-    key_cert_pair.cert_chain = cert_chain;
-    self->c_creds =
-        grpc_ssl_credentials_create(root_certs, &key_cert_pair, NULL);
-  } else {
-    self->c_creds = grpc_ssl_credentials_create(root_certs, NULL, NULL);
-  }
-  if (!self->c_creds) {
-    Py_DECREF(self);
-    PyErr_SetString(PyExc_RuntimeError, "couldn't create ssl credentials");
-    return NULL;
-  }
-  return self;
-}
-
-ClientCredentials *pygrpc_ClientCredentials_composite(
+CallCredentials *pygrpc_CallCredentials_composite(
     PyTypeObject *type, PyObject *args, PyObject *kwargs) {
-  ClientCredentials *self;
-  ClientCredentials *creds1;
-  ClientCredentials *creds2;
+  CallCredentials *self;
+  CallCredentials *creds1;
+  CallCredentials *creds2;
   static char *keywords[] = {"creds1", "creds2", NULL};
   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!:composite", keywords,
-        &pygrpc_ClientCredentials_type, &creds1,
-        &pygrpc_ClientCredentials_type, &creds2)) {
+        &pygrpc_CallCredentials_type, &creds1,
+        &pygrpc_CallCredentials_type, &creds2)) {
     return NULL;
   }
-  self = (ClientCredentials *)type->tp_alloc(type, 0);
+  self = (CallCredentials *)type->tp_alloc(type, 0);
   self->c_creds =
-      grpc_composite_credentials_create(creds1->c_creds, creds2->c_creds, NULL);
+      grpc_composite_call_credentials_create(
+          creds1->c_creds, creds2->c_creds, NULL);
   if (!self->c_creds) {
     Py_DECREF(self);
     PyErr_SetString(PyExc_RuntimeError, "couldn't create composite credentials");
@@ -168,9 +124,9 @@ ClientCredentials *pygrpc_ClientCredentials_composite(
   return self;
 }
 
-ClientCredentials *pygrpc_ClientCredentials_compute_engine(
+CallCredentials *pygrpc_CallCredentials_compute_engine(
     PyTypeObject *type, PyObject *ignored) {
-  ClientCredentials *self = (ClientCredentials *)type->tp_alloc(type, 0);
+  CallCredentials *self = (CallCredentials *)type->tp_alloc(type, 0);
   self->c_creds = grpc_google_compute_engine_credentials_create(NULL);
   if (!self->c_creds) {
     Py_DECREF(self);
@@ -182,9 +138,9 @@ ClientCredentials *pygrpc_ClientCredentials_compute_engine(
 }
 
 /* TODO: Rename this credentials to something like service_account_jwt_access */
-ClientCredentials *pygrpc_ClientCredentials_jwt(
+CallCredentials *pygrpc_CallCredentials_jwt(
     PyTypeObject *type, PyObject *args, PyObject *kwargs) {
-  ClientCredentials *self;
+  CallCredentials *self;
   const char *json_key;
   double lifetime;
   static char *keywords[] = {"json_key", "token_lifetime", NULL};
@@ -192,7 +148,7 @@ ClientCredentials *pygrpc_ClientCredentials_jwt(
         &json_key, &lifetime)) {
     return NULL;
   }
-  self = (ClientCredentials *)type->tp_alloc(type, 0);
+  self = (CallCredentials *)type->tp_alloc(type, 0);
   self->c_creds = grpc_service_account_jwt_access_credentials_create(
       json_key, pygrpc_cast_double_to_gpr_timespec(lifetime), NULL);
   if (!self->c_creds) {
@@ -203,16 +159,16 @@ ClientCredentials *pygrpc_ClientCredentials_jwt(
   return self;
 }
 
-ClientCredentials *pygrpc_ClientCredentials_refresh_token(
+CallCredentials *pygrpc_CallCredentials_refresh_token(
     PyTypeObject *type, PyObject *args, PyObject *kwargs) {
-  ClientCredentials *self;
+  CallCredentials *self;
   const char *json_refresh_token;
   static char *keywords[] = {"json_refresh_token", NULL};
   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:refresh_token", keywords,
         &json_refresh_token)) {
     return NULL;
   }
-  self = (ClientCredentials *)type->tp_alloc(type, 0);
+  self = (CallCredentials *)type->tp_alloc(type, 0);
   self->c_creds =
       grpc_google_refresh_token_credentials_create(json_refresh_token, NULL);
   if (!self->c_creds) {
@@ -224,9 +180,9 @@ ClientCredentials *pygrpc_ClientCredentials_refresh_token(
   return self;
 }
 
-ClientCredentials *pygrpc_ClientCredentials_iam(
+CallCredentials *pygrpc_CallCredentials_iam(
     PyTypeObject *type, PyObject *args, PyObject *kwargs) {
-  ClientCredentials *self;
+  CallCredentials *self;
   const char *authorization_token;
   const char *authority_selector;
   static char *keywords[] = {"authorization_token", "authority_selector", NULL};
@@ -234,7 +190,7 @@ ClientCredentials *pygrpc_ClientCredentials_iam(
         &authorization_token, &authority_selector)) {
     return NULL;
   }
-  self = (ClientCredentials *)type->tp_alloc(type, 0);
+  self = (CallCredentials *)type->tp_alloc(type, 0);
   self->c_creds = grpc_google_iam_credentials_create(authorization_token,
                                                      authority_selector, NULL);
   if (!self->c_creds) {
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/channel.c b/src/python/grpcio/grpc/_adapter/_c/types/channel.c
index 79d39c4391dfd4eb26d513601273d6bbf49f7509..c4db2a0dfde3e9b53fe1332946716390d2676ac5 100644
--- a/src/python/grpcio/grpc/_adapter/_c/types/channel.c
+++ b/src/python/grpcio/grpc/_adapter/_c/types/channel.c
@@ -94,11 +94,11 @@ Channel *pygrpc_Channel_new(
   Channel *self;
   const char *target;
   PyObject *py_args;
-  ClientCredentials *creds = NULL;
+  ChannelCredentials *creds = NULL;
   grpc_channel_args c_args;
   char *keywords[] = {"target", "args", "creds", NULL};
   if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO|O!:Channel", keywords,
-        &target, &py_args, &pygrpc_ClientCredentials_type, &creds)) {
+        &target, &py_args, &pygrpc_ChannelCredentials_type, &creds)) {
     return NULL;
   }
   if (!pygrpc_produce_channel_args(py_args, &c_args)) {
diff --git a/src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c b/src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c
new file mode 100644
index 0000000000000000000000000000000000000000..83b1fc0406af9f4f9c9240bff4790ac972b94982
--- /dev/null
+++ b/src/python/grpcio/grpc/_adapter/_c/types/channel_credentials.c
@@ -0,0 +1,165 @@
+/*
+ *
+ * Copyright 2015, Google Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include "grpc/_adapter/_c/types.h"
+
+#define PY_SSIZE_T_CLEAN
+#include <Python.h>
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+
+
+PyMethodDef pygrpc_ChannelCredentials_methods[] = {
+    {"google_default", (PyCFunction)pygrpc_ChannelCredentials_google_default,
+     METH_CLASS|METH_NOARGS, ""},
+    {"ssl", (PyCFunction)pygrpc_ChannelCredentials_ssl,
+     METH_CLASS|METH_KEYWORDS, ""},
+    {"composite", (PyCFunction)pygrpc_ChannelCredentials_composite,
+     METH_CLASS|METH_KEYWORDS, ""},
+    {NULL}
+};
+
+const char pygrpc_ChannelCredentials_doc[] = "";
+PyTypeObject pygrpc_ChannelCredentials_type = {
+    PyObject_HEAD_INIT(NULL)
+    0,                                        /* ob_size */
+    "ChannelCredentials",                     /* tp_name */
+    sizeof(ChannelCredentials),               /* tp_basicsize */
+    0,                                        /* tp_itemsize */
+    (destructor)pygrpc_ChannelCredentials_dealloc, /* tp_dealloc */
+    0,                                        /* tp_print */
+    0,                                        /* tp_getattr */
+    0,                                        /* tp_setattr */
+    0,                                        /* tp_compare */
+    0,                                        /* tp_repr */
+    0,                                        /* tp_as_number */
+    0,                                        /* tp_as_sequence */
+    0,                                        /* tp_as_mapping */
+    0,                                        /* tp_hash */
+    0,                                        /* tp_call */
+    0,                                        /* tp_str */
+    0,                                        /* tp_getattro */
+    0,                                        /* tp_setattro */
+    0,                                        /* tp_as_buffer */
+    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
+    pygrpc_ChannelCredentials_doc,             /* tp_doc */
+    0,                                        /* tp_traverse */
+    0,                                        /* tp_clear */
+    0,                                        /* tp_richcompare */
+    0,                                        /* tp_weaklistoffset */
+    0,                                        /* tp_iter */
+    0,                                        /* tp_iternext */
+    pygrpc_ChannelCredentials_methods,         /* tp_methods */
+    0,                                        /* tp_members */
+    0,                                        /* tp_getset */
+    0,                                        /* tp_base */
+    0,                                        /* tp_dict */
+    0,                                        /* tp_descr_get */
+    0,                                        /* tp_descr_set */
+    0,                                        /* tp_dictoffset */
+    0,                                        /* tp_init */
+    0,                                        /* tp_alloc */
+    0                                         /* tp_new */
+};
+
+void pygrpc_ChannelCredentials_dealloc(ChannelCredentials *self) {
+  grpc_channel_credentials_release(self->c_creds);
+  self->ob_type->tp_free((PyObject *)self);
+}
+
+ChannelCredentials *pygrpc_ChannelCredentials_google_default(
+    PyTypeObject *type, PyObject *ignored) {
+  ChannelCredentials *self = (ChannelCredentials *)type->tp_alloc(type, 0);
+  self->c_creds = grpc_google_default_credentials_create();
+  if (!self->c_creds) {
+    Py_DECREF(self);
+    PyErr_SetString(PyExc_RuntimeError,
+                    "couldn't create Google default credentials");
+    return NULL;
+  }
+  return self;
+}
+
+ChannelCredentials *pygrpc_ChannelCredentials_ssl(
+    PyTypeObject *type, PyObject *args, PyObject *kwargs) {
+  ChannelCredentials *self;
+  const char *root_certs;
+  const char *private_key = NULL;
+  const char *cert_chain = NULL;
+  grpc_ssl_pem_key_cert_pair key_cert_pair;
+  static char *keywords[] = {"root_certs", "private_key", "cert_chain", NULL};
+  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z|zz:ssl", keywords,
+        &root_certs, &private_key, &cert_chain)) {
+    return NULL;
+  }
+  self = (ChannelCredentials *)type->tp_alloc(type, 0);
+  if (private_key && cert_chain) {
+    key_cert_pair.private_key = private_key;
+    key_cert_pair.cert_chain = cert_chain;
+    self->c_creds =
+        grpc_ssl_credentials_create(root_certs, &key_cert_pair, NULL);
+  } else {
+    self->c_creds = grpc_ssl_credentials_create(root_certs, NULL, NULL);
+  }
+  if (!self->c_creds) {
+    Py_DECREF(self);
+    PyErr_SetString(PyExc_RuntimeError, "couldn't create ssl credentials");
+    return NULL;
+  }
+  return self;
+}
+
+ChannelCredentials *pygrpc_ChannelCredentials_composite(
+    PyTypeObject *type, PyObject *args, PyObject *kwargs) {
+  ChannelCredentials *self;
+  ChannelCredentials *creds1;
+  CallCredentials *creds2;
+  static char *keywords[] = {"creds1", "creds2", NULL};
+  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O!:composite", keywords,
+        &pygrpc_ChannelCredentials_type, &creds1,
+        &pygrpc_CallCredentials_type, &creds2)) {
+    return NULL;
+  }
+  self = (ChannelCredentials *)type->tp_alloc(type, 0);
+  self->c_creds =
+      grpc_composite_channel_credentials_create(
+          creds1->c_creds, creds2->c_creds, NULL);
+  if (!self->c_creds) {
+    Py_DECREF(self);
+    PyErr_SetString(
+        PyExc_RuntimeError, "couldn't create composite credentials");
+    return NULL;
+  }
+  return self;
+}
+
diff --git a/src/python/grpcio/grpc/_adapter/_intermediary_low.py b/src/python/grpcio/grpc/_adapter/_intermediary_low.py
index e2feec6ffba1fa89161d20bbcff2703f90c71e9e..5634c2024d350f6d19d5f28ead406a2746f540e9 100644
--- a/src/python/grpcio/grpc/_adapter/_intermediary_low.py
+++ b/src/python/grpcio/grpc/_adapter/_intermediary_low.py
@@ -253,10 +253,10 @@ class Server(object):
 
 
 class ClientCredentials(object):
-  """Adapter from old _low.ClientCredentials interface to new _low.ClientCredentials."""
+  """Adapter from old _low.ClientCredentials interface to new _low.ChannelCredentials."""
 
   def __init__(self, root_certificates, private_key, certificate_chain):
-    self._internal = _low.ClientCredentials.ssl(root_certificates, private_key, certificate_chain)
+    self._internal = _low.ChannelCredentials.ssl(root_certificates, private_key, certificate_chain)
 
 
 class ServerCredentials(object):
diff --git a/src/python/grpcio/grpc/_adapter/_low.py b/src/python/grpcio/grpc/_adapter/_low.py
index 70ceb2a9113af0a1863bf8adbe49303c9b764d58..57146aaefe8020933548c6803cbefa37f60510f2 100644
--- a/src/python/grpcio/grpc/_adapter/_low.py
+++ b/src/python/grpcio/grpc/_adapter/_low.py
@@ -33,7 +33,8 @@ from grpc._adapter import _types
 
 _USER_AGENT = 'Python-gRPC-{}'.format(_grpcio_metadata.__version__)
 
-ClientCredentials = _c.ClientCredentials
+ChannelCredentials = _c.ChannelCredentials
+CallCredentials = _c.CallCredentials
 ServerCredentials = _c.ServerCredentials
 
 
diff --git a/src/python/grpcio/grpc/_adapter/_types.py b/src/python/grpcio/grpc/_adapter/_types.py
index 5470d2de4a3d671a05ad5895e99ecc378c81a6e0..ca0fa066bc8e7d6bf005acde6898c4d6304276a8 100644
--- a/src/python/grpcio/grpc/_adapter/_types.py
+++ b/src/python/grpcio/grpc/_adapter/_types.py
@@ -323,6 +323,14 @@ class Call:
     """
     return None
 
+  def set_credentials(self, creds):
+    """Set per-call credentials.
+
+    Args:
+      creds (CallCredentials): Credentials to be set for this call.
+    """
+    return None
+
 
 class Channel:
   __metaclass__ = abc.ABCMeta
@@ -334,7 +342,7 @@ class Channel:
     Args:
       target (str): ...
       args (sequence of 2-sequence of str, (str|integer)): ...
-      credentials (ClientCredentials): If None, create an insecure channel,
+      credentials (ChannelCredentials): If None, create an insecure channel,
         else create a secure channel using the client credentials.
     """
 
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx
index ed037b660a24b90a28466f46345fbc328fc7ee9f..51c46681388f43e6ed720d2da557fce7f8101167 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/call.pyx
@@ -29,6 +29,7 @@
 
 cimport cpython
 
+from grpc._cython._cygrpc cimport credentials
 from grpc._cython._cygrpc cimport grpc
 from grpc._cython._cygrpc cimport records
 
@@ -73,6 +74,11 @@ cdef class Call:
     else:
       return grpc.grpc_call_cancel(self.c_call, NULL)
 
+  def set_credentials(
+      self, credentials.CallCredentials call_credentials not None):
+    return grpc.grpc_call_set_credentials(
+        self.c_call, call_credentials.c_credentials)
+
   def __dealloc__(self):
     if self.c_call != NULL:
       grpc.grpc_call_destroy(self.c_call)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
index b52ddb6bcd4de4b4c28eb034c556a12b1cfb45fd..e25db3e2a442095aec7c367afcc6b262e6a0474d 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
@@ -37,7 +37,7 @@ from grpc._cython._cygrpc cimport records
 cdef class Channel:
 
   def __cinit__(self, target, records.ChannelArgs arguments=None,
-                credentials.ClientCredentials client_credentials=None):
+                credentials.ChannelCredentials channel_credentials=None):
     cdef grpc.grpc_channel_args *c_arguments = NULL
     self.c_channel = NULL
     self.references = []
@@ -49,13 +49,13 @@ cdef class Channel:
       target = target.encode()
     else:
       raise TypeError("expected target to be str or bytes")
-    if client_credentials is None:
+    if channel_credentials is None:
       self.c_channel = grpc.grpc_insecure_channel_create(target, c_arguments,
                                                          NULL)
     else:
       self.c_channel = grpc.grpc_secure_channel_create(
-          client_credentials.c_credentials, target, c_arguments, NULL)
-      self.references.append(client_credentials)
+          channel_credentials.c_credentials, target, c_arguments, NULL)
+      self.references.append(channel_credentials)
     self.references.append(target)
     self.references.append(arguments)
 
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd
index 6b74a267e0bb9ad568d80e203902d7f0e0f27d26..7a9fa7b76d01b3b3596be369fe77ac3481818a6b 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pxd
@@ -30,13 +30,19 @@
 from grpc._cython._cygrpc cimport grpc
 
 
-cdef class ClientCredentials:
+cdef class ChannelCredentials:
 
-  cdef grpc.grpc_credentials *c_credentials
+  cdef grpc.grpc_channel_credentials *c_credentials
   cdef grpc.grpc_ssl_pem_key_cert_pair c_ssl_pem_key_cert_pair
   cdef list references
 
 
+cdef class CallCredentials:
+
+  cdef grpc.grpc_call_credentials *c_credentials
+  cdef list references
+
+
 cdef class ServerCredentials:
 
   cdef grpc.grpc_server_credentials *c_credentials
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
index 608207f0a2234ad22d6c9b48efc10c5424892174..e9836fec2cf7ed08446373d67634a56d4e57dafd 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/credentials.pyx
@@ -31,7 +31,7 @@ from grpc._cython._cygrpc cimport grpc
 from grpc._cython._cygrpc cimport records
 
 
-cdef class ClientCredentials:
+cdef class ChannelCredentials:
 
   def __cinit__(self):
     self.c_credentials = NULL
@@ -47,7 +47,24 @@ cdef class ClientCredentials:
 
   def __dealloc__(self):
     if self.c_credentials != NULL:
-      grpc.grpc_credentials_release(self.c_credentials)
+      grpc.grpc_channel_credentials_release(self.c_credentials)
+
+
+cdef class CallCredentials:
+
+  def __cinit__(self):
+    self.c_credentials = NULL
+    self.references = []
+
+  # The object *can* be invalid in Python if we fail to make the credentials
+  # (and the core thus returns NULL credentials). Used primarily for debugging.
+  @property
+  def is_valid(self):
+    return self.c_credentials != NULL
+
+  def __dealloc__(self):
+    if self.c_credentials != NULL:
+      grpc.grpc_call_credentials_release(self.c_credentials)
 
 
 cdef class ServerCredentials:
@@ -60,12 +77,12 @@ cdef class ServerCredentials:
       grpc.grpc_server_credentials_release(self.c_credentials)
 
 
-def client_credentials_google_default():
-  cdef ClientCredentials credentials = ClientCredentials();
+def channel_credentials_google_default():
+  cdef ChannelCredentials credentials = ChannelCredentials();
   credentials.c_credentials = grpc.grpc_google_default_credentials_create()
   return credentials
 
-def client_credentials_ssl(pem_root_certificates,
+def channel_credentials_ssl(pem_root_certificates,
                            records.SslPemKeyCertPair ssl_pem_key_cert_pair):
   if pem_root_certificates is None:
     pass
@@ -75,7 +92,7 @@ def client_credentials_ssl(pem_root_certificates,
     pem_root_certificates = pem_root_certificates.encode()
   else:
     raise TypeError("expected str or bytes for pem_root_certificates")
-  cdef ClientCredentials credentials = ClientCredentials()
+  cdef ChannelCredentials credentials = ChannelCredentials()
   cdef const char *c_pem_root_certificates = NULL
   if pem_root_certificates is not None:
     c_pem_root_certificates = pem_root_certificates
@@ -88,26 +105,38 @@ def client_credentials_ssl(pem_root_certificates,
     credentials.c_credentials = grpc.grpc_ssl_credentials_create(
       c_pem_root_certificates, NULL, NULL)
 
-def client_credentials_composite_credentials(
-    ClientCredentials credentials_1 not None,
-    ClientCredentials credentials_2 not None):
+def channel_credentials_composite(
+    ChannelCredentials credentials_1 not None,
+    CallCredentials credentials_2 not None):
+  if not credentials_1.is_valid or not credentials_2.is_valid:
+    raise ValueError("passed credentials must both be valid")
+  cdef ChannelCredentials credentials = ChannelCredentials()
+  credentials.c_credentials = grpc.grpc_composite_channel_credentials_create(
+      credentials_1.c_credentials, credentials_2.c_credentials, NULL)
+  credentials.references.append(credentials_1)
+  credentials.references.append(credentials_2)
+  return credentials
+
+def call_credentials_composite(
+    CallCredentials credentials_1 not None,
+    CallCredentials credentials_2 not None):
   if not credentials_1.is_valid or not credentials_2.is_valid:
     raise ValueError("passed credentials must both be valid")
-  cdef ClientCredentials credentials = ClientCredentials()
-  credentials.c_credentials = grpc.grpc_composite_credentials_create(
+  cdef CallCredentials credentials = CallCredentials()
+  credentials.c_credentials = grpc.grpc_composite_call_credentials_create(
       credentials_1.c_credentials, credentials_2.c_credentials, NULL)
   credentials.references.append(credentials_1)
   credentials.references.append(credentials_2)
   return credentials
 
-def client_credentials_google_compute_engine():
-  cdef ClientCredentials credentials = ClientCredentials()
+def call_credentials_google_compute_engine():
+  cdef CallCredentials credentials = CallCredentials()
   credentials.c_credentials = (
       grpc.grpc_google_compute_engine_credentials_create(NULL))
   return credentials
 
 #TODO rename to something like client_credentials_service_account_jwt_access.
-def client_credentials_service_account_jwt_access(
+def call_credentials_service_account_jwt_access(
     json_key, records.Timespec token_lifetime not None):
   if isinstance(json_key, bytes):
     pass
@@ -115,27 +144,27 @@ def client_credentials_service_account_jwt_access(
     json_key = json_key.encode()
   else:
     raise TypeError("expected json_key to be str or bytes")
-  cdef ClientCredentials credentials = ClientCredentials()
+  cdef CallCredentials credentials = CallCredentials()
   credentials.c_credentials = (
       grpc.grpc_service_account_jwt_access_credentials_create(
           json_key, token_lifetime.c_time, NULL))
   credentials.references.append(json_key)
   return credentials
 
-def client_credentials_google_refresh_token(json_refresh_token):
+def call_credentials_google_refresh_token(json_refresh_token):
   if isinstance(json_refresh_token, bytes):
     pass
   elif isinstance(json_refresh_token, basestring):
     json_refresh_token = json_refresh_token.encode()
   else:
     raise TypeError("expected json_refresh_token to be str or bytes")
-  cdef ClientCredentials credentials = ClientCredentials()
+  cdef CallCredentials credentials = CallCredentials()
   credentials.c_credentials = grpc.grpc_google_refresh_token_credentials_create(
       json_refresh_token, NULL)
   credentials.references.append(json_refresh_token)
   return credentials
 
-def client_credentials_google_iam(authorization_token, authority_selector):
+def call_credentials_google_iam(authorization_token, authority_selector):
   if isinstance(authorization_token, bytes):
     pass
   elif isinstance(authorization_token, basestring):
@@ -148,7 +177,7 @@ def client_credentials_google_iam(authorization_token, authority_selector):
     authority_selector = authority_selector.encode()
   else:
     raise TypeError("expected authority_selector to be str or bytes")
-  cdef ClientCredentials credentials = ClientCredentials()
+  cdef CallCredentials credentials = CallCredentials()
   credentials.c_credentials = grpc.grpc_google_iam_credentials_create(
       authorization_token, authority_selector, NULL)
   credentials.references.append(authorization_token)
diff --git a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
index 62d40e7a58e6e71d675169317b97e8f2fc2620e1..36aea81a6c0d8de77d6a187426d9b096c76f7638 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
@@ -316,32 +316,40 @@ cdef extern from "grpc/grpc_security.h":
     const char *private_key
     const char *certificate_chain "cert_chain"
 
-  ctypedef struct grpc_credentials:
+  ctypedef struct grpc_channel_credentials:
     # We don't care about the internals (and in fact don't know them)
     pass
 
-  grpc_credentials *grpc_google_default_credentials_create()
-  grpc_credentials *grpc_ssl_credentials_create(
+  ctypedef struct grpc_call_credentials:
+    # We don't care about the internals (and in fact don't know them)
+    pass
+
+  grpc_channel_credentials *grpc_google_default_credentials_create()
+  grpc_channel_credentials *grpc_ssl_credentials_create(
       const char *pem_root_certs, grpc_ssl_pem_key_cert_pair *pem_key_cert_pair,
       void *reserved)
+  grpc_channel_credentials *grpc_composite_channel_credentials_create(
+      grpc_channel_credentials *creds1, grpc_call_credentials *creds2,
+      void *reserved)
+  void grpc_channel_credentials_release(grpc_channel_credentials *creds)
 
-  grpc_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
-                                                      grpc_credentials *creds2,
-                                                      void *reserved)
-  grpc_credentials *grpc_google_compute_engine_credentials_create(
+  grpc_call_credentials *grpc_composite_call_credentials_create(
+      grpc_call_credentials *creds1, grpc_call_credentials *creds2,
+      void *reserved)
+  grpc_call_credentials *grpc_google_compute_engine_credentials_create(
       void *reserved)
-  grpc_credentials *grpc_service_account_jwt_access_credentials_create(
+  grpc_call_credentials *grpc_service_account_jwt_access_credentials_create(
       const char *json_key,
       gpr_timespec token_lifetime, void *reserved)
-  grpc_credentials *grpc_google_refresh_token_credentials_create(
+  grpc_call_credentials *grpc_google_refresh_token_credentials_create(
       const char *json_refresh_token, void *reserved)
-  grpc_credentials *grpc_google_iam_credentials_create(
+  grpc_call_credentials *grpc_google_iam_credentials_create(
       const char *authorization_token, const char *authority_selector,
       void *reserved)
-  void grpc_credentials_release(grpc_credentials *creds)
+  void grpc_call_credentials_release(grpc_call_credentials *creds)
 
   grpc_channel *grpc_secure_channel_create(
-      grpc_credentials *creds, const char *target,
+      grpc_channel_credentials *creds, const char *target,
       const grpc_channel_args *args, void *reserved)
 
   ctypedef struct grpc_server_credentials:
@@ -358,4 +366,4 @@ cdef extern from "grpc/grpc_security.h":
                                         grpc_server_credentials *creds)
 
   grpc_call_error grpc_call_set_credentials(grpc_call *call,
-                                            grpc_credentials *creds)
+                                            grpc_call_credentials *creds)
diff --git a/src/python/grpcio/grpc/_cython/cygrpc.pyx b/src/python/grpcio/grpc/_cython/cygrpc.pyx
index 1ef2997db5162324696acef184efc124364049d4..b20dda8a95875dcfdf66687ae52a00967f7037fb 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pyx
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx
@@ -70,21 +70,24 @@ operation_receive_close_on_server = records.operation_receive_close_on_server
 
 Operations = records.Operations
 
-ClientCredentials = credentials.ClientCredentials
+CallCredentials = credentials.CallCredentials
+ChannelCredentials = credentials.ChannelCredentials
 ServerCredentials = credentials.ServerCredentials
 
-client_credentials_google_default = (
-    credentials.client_credentials_google_default)
-client_credentials_ssl = credentials.client_credentials_ssl
-client_credentials_composite_credentials = (
-    credentials.client_credentials_composite_credentials)
-client_credentials_google_compute_engine = (
-    credentials.client_credentials_google_compute_engine)
-client_credentials_jwt_access = (
-    credentials.client_credentials_service_account_jwt_access)
-client_credentials_refresh_token = (
-    credentials.client_credentials_google_refresh_token)
-client_credentials_google_iam = credentials.client_credentials_google_iam
+channel_credentials_google_default = (
+    credentials.channel_credentials_google_default)
+channel_credentials_ssl = credentials.channel_credentials_ssl
+channel_credentials_composite = (
+    credentials.channel_credentials_composite)
+call_credentials_composite = (
+    credentials.call_credentials_composite)
+call_credentials_google_compute_engine = (
+    credentials.call_credentials_google_compute_engine)
+call_credentials_jwt_access = (
+    credentials.call_credentials_service_account_jwt_access)
+call_credentials_refresh_token = (
+    credentials.call_credentials_google_refresh_token)
+call_credentials_google_iam = credentials.call_credentials_google_iam
 server_credentials_ssl = credentials.server_credentials_ssl
 
 CompletionQueue = completion_queue.CompletionQueue
diff --git a/src/python/grpcio/grpc/beta/interfaces.py b/src/python/grpcio/grpc/beta/interfaces.py
index 07c8618f70ccc8110e36d3b43e861f4364f2b626..d4ca56500ffd488c4856afe59e29096d7f479757 100644
--- a/src/python/grpcio/grpc/beta/interfaces.py
+++ b/src/python/grpcio/grpc/beta/interfaces.py
@@ -100,8 +100,11 @@ def grpc_call_options(disable_compression=False, credentials=None):
     disable_compression: A boolean indicating whether or not compression should
       be disabled for the request object of the RPC. Only valid for
       request-unary RPCs.
-    credentials: A ClientCredentials object to use for the invoked RPC.
+    credentials: Reserved for gRPC per-call credentials. The type for this does
+      not exist yet at the Python level.
   """
+  if credentials is not None:
+    raise ValueError('`credentials` is a reserved argument')
   return GRPCCallOptions(disable_compression, None, credentials)
 
 
diff --git a/src/python/grpcio/grpc/framework/interfaces/face/face.py b/src/python/grpcio/grpc/framework/interfaces/face/face.py
index bc9a434a760bd923afbb12c41bec4e5ee3ca9735..3b402356d2d0722312229a271c7b5c5ac569335d 100644
--- a/src/python/grpcio/grpc/framework/interfaces/face/face.py
+++ b/src/python/grpcio/grpc/framework/interfaces/face/face.py
@@ -117,6 +117,10 @@ class AbortionError(Exception):
     self.code = code
     self.details = details
 
+  def __str__(self):
+    return '%s(code=%s, details="%s")' % (
+        self.__class__.__name__, self.code, self.details)
+
 
 class CancellationError(AbortionError):
   """Indicates that an RPC has been cancelled."""
diff --git a/src/python/grpcio/setup.py b/src/python/grpcio/setup.py
index 97fa4fe6b3ffc5db3805271570c6b762a07c6dc9..ec68eb67555c5c9b530f9d0f0a9e7476e17b6f92 100644
--- a/src/python/grpcio/setup.py
+++ b/src/python/grpcio/setup.py
@@ -52,7 +52,8 @@ _C_EXTENSION_SOURCES = (
     'grpc/_adapter/_c/module.c',
     'grpc/_adapter/_c/types.c',
     'grpc/_adapter/_c/utility.c',
-    'grpc/_adapter/_c/types/client_credentials.c',
+    'grpc/_adapter/_c/types/call_credentials.c',
+    'grpc/_adapter/_c/types/channel_credentials.c',
     'grpc/_adapter/_c/types/server_credentials.c',
     'grpc/_adapter/_c/types/completion_queue.c',
     'grpc/_adapter/_c/types/call.c',
diff --git a/src/python/grpcio_test/grpc_interop/credentials/server1.pem b/src/python/grpcio_test/grpc_interop/credentials/server1.pem
index 8e582e571f643ca3fb6042a786c709a53f5afcf3..f3d43fcc5beadd98542abdaa32acfb555b807559 100755
--- a/src/python/grpcio_test/grpc_interop/credentials/server1.pem
+++ b/src/python/grpcio_test/grpc_interop/credentials/server1.pem
@@ -1,16 +1,16 @@
 -----BEGIN CERTIFICATE-----
-MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET
-MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
-dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5
-MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
-BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl
-c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs
-JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO
-RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30
-3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL
-BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6
-b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ
-KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS
-wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e
-aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s=
+MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
+MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx
+MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
+BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50
+ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco
+LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg
+zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd
+9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw
+CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy
+em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G
+CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6
+hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh
+y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8
 -----END CERTIFICATE-----
diff --git a/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py b/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py
index fad57da9d069813b85084ab362fbf96fefe4195f..5916a9e3eaef288efc083b4d1325f9f6a09a5036 100644
--- a/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py
+++ b/src/python/grpcio_test/grpc_test/beta/_beta_features_test.py
@@ -181,24 +181,21 @@ class BetaFeaturesTest(unittest.TestCase):
     self._server.stop(test_constants.SHORT_TIMEOUT).wait()
 
   def test_unary_unary(self):
-    call_options = interfaces.grpc_call_options(
-        disable_compression=True, credentials=self._client_credentials)
+    call_options = interfaces.grpc_call_options(disable_compression=True)
     response = getattr(self._dynamic_stub, _UNARY_UNARY)(
         _REQUEST, test_constants.LONG_TIMEOUT, protocol_options=call_options)
     self.assertEqual(_RESPONSE, response)
     self.assertIsNotNone(self._servicer.peer())
 
   def test_unary_stream(self):
-    call_options = interfaces.grpc_call_options(
-        disable_compression=True, credentials=self._client_credentials)
+    call_options = interfaces.grpc_call_options(disable_compression=True)
     response_iterator = getattr(self._dynamic_stub, _UNARY_STREAM)(
         _REQUEST, test_constants.LONG_TIMEOUT, protocol_options=call_options)
     self._servicer.block_until_serviced()
     self.assertIsNotNone(self._servicer.peer())
 
   def test_stream_unary(self):
-    call_options = interfaces.grpc_call_options(
-        credentials=self._client_credentials)
+    call_options = interfaces.grpc_call_options()
     request_iterator = _BlockingIterator(iter((_REQUEST,)))
     response_future = getattr(self._dynamic_stub, _STREAM_UNARY).future(
         request_iterator, test_constants.LONG_TIMEOUT,
@@ -212,8 +209,7 @@ class BetaFeaturesTest(unittest.TestCase):
     self.assertEqual(_RESPONSE, response_future.result())
 
   def test_stream_stream(self):
-    call_options = interfaces.grpc_call_options(
-        credentials=self._client_credentials)
+    call_options = interfaces.grpc_call_options()
     request_iterator = _BlockingIterator(iter((_REQUEST,)))
     response_iterator = getattr(self._dynamic_stub, _STREAM_STREAM)(
         request_iterator, test_constants.SHORT_TIMEOUT,
diff --git a/src/python/grpcio_test/grpc_test/credentials/server1.pem b/src/python/grpcio_test/grpc_test/credentials/server1.pem
index 8e582e571f643ca3fb6042a786c709a53f5afcf3..f3d43fcc5beadd98542abdaa32acfb555b807559 100755
--- a/src/python/grpcio_test/grpc_test/credentials/server1.pem
+++ b/src/python/grpcio_test/grpc_test/credentials/server1.pem
@@ -1,16 +1,16 @@
 -----BEGIN CERTIFICATE-----
-MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET
-MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
-dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5
-MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
-BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl
-c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs
-JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO
-RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30
-3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL
-BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6
-b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ
-KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS
-wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e
-aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s=
+MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
+MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx
+MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
+BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50
+ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco
+LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg
+zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd
+9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw
+CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy
+em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G
+CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6
+hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh
+y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8
 -----END CERTIFICATE-----
diff --git a/src/ruby/bin/apis/pubsub_demo.rb b/src/ruby/bin/apis/pubsub_demo.rb
index a039d036ace8d6749ec96c75a85289b961ed8e2b..003e91a6b34b0dd2fefc0173c8b93d84bc2b1a49 100755
--- a/src/ruby/bin/apis/pubsub_demo.rb
+++ b/src/ruby/bin/apis/pubsub_demo.rb
@@ -66,7 +66,7 @@ end
 
 # creates a SSL Credentials from the production certificates.
 def ssl_creds
-  GRPC::Core::Credentials.new(load_prod_cert)
+  GRPC::Core::ChannelCredentials.new(load_prod_cert)
 end
 
 # Builds the metadata authentication update proc.
diff --git a/src/ruby/bin/math_client.rb b/src/ruby/bin/math_client.rb
index 0ebd26f7806480d9b03091e95871ef223c2f3402..d7e00e429384f01bd475f8858a74f1ee4eb09ce7 100755
--- a/src/ruby/bin/math_client.rb
+++ b/src/ruby/bin/math_client.rb
@@ -102,7 +102,7 @@ end
 
 def test_creds
   certs = load_test_certs
-  GRPC::Core::Credentials.new(certs[0])
+  GRPC::Core::ChannelCredentials.new(certs[0])
 end
 
 def main
diff --git a/src/ruby/bin/noproto_client.rb b/src/ruby/bin/noproto_client.rb
index 390a9c59c3b66d9104a468270d630a3e224f4688..3aa11870c081ec3f5fb2ed541aedced9cf7025a3 100755
--- a/src/ruby/bin/noproto_client.rb
+++ b/src/ruby/bin/noproto_client.rb
@@ -68,7 +68,7 @@ end
 
 def test_creds
   certs = load_test_certs
-  GRPC::Core::Credentials.new(certs[0])
+  GRPC::Core::ChannelCredentials.new(certs[0])
 end
 
 def main
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index 6b5beb6f5d74294566a5922dae5145ce2afdb16e..40364328ee8d9a3b0209de537daf2d18348c945e 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -139,7 +139,15 @@ static const rb_data_type_t grpc_rb_md_ary_data_type = {
      {NULL, NULL}},
     NULL,
     NULL,
-    0};
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
+    /* it is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because
+     * grpc_rb_call_destroy
+     * touches a hash object.
+     * TODO(yugui) Directly use st_table and call the free function earlier?
+     */
+    0,
+#endif
+};
 
 /* Describes grpc_call struct for RTypedData */
 static const rb_data_type_t grpc_call_data_type = {
@@ -148,12 +156,15 @@ static const rb_data_type_t grpc_call_data_type = {
      {NULL, NULL}},
     NULL,
     NULL,
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
     /* it is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because
      * grpc_rb_call_destroy
      * touches a hash object.
      * TODO(yugui) Directly use st_table and call the free function earlier?
      */
-    0};
+    0,
+#endif
+};
 
 /* Error code details is a hash containing text strings describing errors */
 VALUE rb_error_code_details;
diff --git a/src/ruby/ext/grpc/rb_channel.c b/src/ruby/ext/grpc/rb_channel.c
index 90afdc3fe112e9b65cc1f4073a930f34206987db..d5d82421f59188fd693474114354d6dee236f800 100644
--- a/src/ruby/ext/grpc/rb_channel.c
+++ b/src/ruby/ext/grpc/rb_channel.c
@@ -41,8 +41,8 @@
 #include "rb_grpc.h"
 #include "rb_call.h"
 #include "rb_channel_args.h"
+#include "rb_channel_credentials.h"
 #include "rb_completion_queue.h"
-#include "rb_credentials.h"
 #include "rb_server.h"
 
 /* id_channel is the name of the hidden ivar that preserves a reference to the
@@ -111,7 +111,9 @@ static rb_data_type_t grpc_channel_data_type = {
     {grpc_rb_channel_mark, grpc_rb_channel_free, GRPC_RB_MEMSIZE_UNAVAILABLE,
      {NULL, NULL}},
     NULL, NULL,
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
     RUBY_TYPED_FREE_IMMEDIATELY
+#endif
 };
 
 /* Allocates grpc_rb_channel instances. */
@@ -134,8 +136,8 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) {
   VALUE credentials = Qnil;
   VALUE target = Qnil;
   grpc_rb_channel *wrapper = NULL;
-  grpc_credentials *creds = NULL;
   grpc_channel *ch = NULL;
+  grpc_channel_credentials *creds = NULL;
   char *target_chars = NULL;
   grpc_channel_args args;
   MEMZERO(&args, grpc_channel_args, 1);
@@ -149,7 +151,7 @@ static VALUE grpc_rb_channel_init(int argc, VALUE *argv, VALUE self) {
   if (credentials == Qnil) {
     ch = grpc_insecure_channel_create(target_chars, &args, NULL);
   } else {
-    creds = grpc_rb_get_wrapped_credentials(credentials);
+    creds = grpc_rb_get_wrapped_channel_credentials(credentials);
     ch = grpc_secure_channel_create(creds, target_chars, &args, NULL);
   }
   if (args.args != NULL) {
diff --git a/src/ruby/ext/grpc/rb_channel_args.c b/src/ruby/ext/grpc/rb_channel_args.c
index 1ba30b69aa2dd653e2baa88b38d782b1354e0c5c..37dd981925ad5ee19b038b672feda8fa69c320a9 100644
--- a/src/ruby/ext/grpc/rb_channel_args.c
+++ b/src/ruby/ext/grpc/rb_channel_args.c
@@ -44,7 +44,9 @@ static rb_data_type_t grpc_rb_channel_args_data_type = {
     {GRPC_RB_GC_NOT_MARKED, GRPC_RB_GC_DONT_FREE, GRPC_RB_MEMSIZE_UNAVAILABLE,
      {NULL, NULL}},
     NULL, NULL,
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
     RUBY_TYPED_FREE_IMMEDIATELY
+#endif
 };
 
 /* A callback the processes the hash key values in channel_args hash */
diff --git a/src/ruby/ext/grpc/rb_credentials.c b/src/ruby/ext/grpc/rb_channel_credentials.c
similarity index 50%
rename from src/ruby/ext/grpc/rb_credentials.c
rename to src/ruby/ext/grpc/rb_channel_credentials.c
index ae757f698666c9327d191b4c438908e9e4dc7c28..072a6f54ab87482b04667b5ad3fd920aa561bdb5 100644
--- a/src/ruby/ext/grpc/rb_credentials.c
+++ b/src/ruby/ext/grpc/rb_channel_credentials.c
@@ -31,7 +31,7 @@
  *
  */
 
-#include "rb_credentials.h"
+#include "rb_channel_credentials.h"
 
 #include <ruby/ruby.h>
 
@@ -40,32 +40,33 @@
 
 #include "rb_grpc.h"
 
-/* grpc_rb_cCredentials is the ruby class that proxies grpc_credentials. */
-static VALUE grpc_rb_cCredentials = Qnil;
+/* grpc_rb_cChannelCredentials is the ruby class that proxies
+   grpc_channel_credentials. */
+static VALUE grpc_rb_cChannelCredentials = Qnil;
 
-/* grpc_rb_credentials wraps a grpc_credentials.  It provides a
+/* grpc_rb_channel_credentials wraps a grpc_channel_credentials.  It provides a
  * peer ruby object, 'mark' to minimize copying when a credential is
  * created from ruby. */
-typedef struct grpc_rb_credentials {
+typedef struct grpc_rb_channel_credentials {
   /* Holder of ruby objects involved in constructing the credentials */
   VALUE mark;
 
   /* The actual credentials */
-  grpc_credentials *wrapped;
-} grpc_rb_credentials;
+  grpc_channel_credentials *wrapped;
+} grpc_rb_channel_credentials;
 
 /* Destroys the credentials instances. */
-static void grpc_rb_credentials_free(void *p) {
-  grpc_rb_credentials *wrapper = NULL;
+static void grpc_rb_channel_credentials_free(void *p) {
+  grpc_rb_channel_credentials *wrapper = NULL;
   if (p == NULL) {
     return;
   };
-  wrapper = (grpc_rb_credentials *)p;
+  wrapper = (grpc_rb_channel_credentials *)p;
 
   /* Delete the wrapped object if the mark object is Qnil, which indicates that
    * no other object is the actual owner. */
   if (wrapper->wrapped != NULL && wrapper->mark == Qnil) {
-    grpc_credentials_release(wrapper->wrapped);
+    grpc_channel_credentials_release(wrapper->wrapped);
     wrapper->wrapped = NULL;
   }
 
@@ -73,12 +74,12 @@ static void grpc_rb_credentials_free(void *p) {
 }
 
 /* Protects the mark object from GC */
-static void grpc_rb_credentials_mark(void *p) {
-  grpc_rb_credentials *wrapper = NULL;
+static void grpc_rb_channel_credentials_mark(void *p) {
+  grpc_rb_channel_credentials *wrapper = NULL;
   if (p == NULL) {
     return;
   }
-  wrapper = (grpc_rb_credentials *)p;
+  wrapper = (grpc_rb_channel_credentials *)p;
 
   /* If it's not already cleaned up, mark the mark object */
   if (wrapper->mark != Qnil) {
@@ -86,29 +87,32 @@ static void grpc_rb_credentials_mark(void *p) {
   }
 }
 
-static rb_data_type_t grpc_rb_credentials_data_type = {
-    "grpc_credentials",
-    {grpc_rb_credentials_mark, grpc_rb_credentials_free,
+static rb_data_type_t grpc_rb_channel_credentials_data_type = {
+    "grpc_channel_credentials",
+    {grpc_rb_channel_credentials_mark, grpc_rb_channel_credentials_free,
      GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}},
     NULL,
     NULL,
-    RUBY_TYPED_FREE_IMMEDIATELY};
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
+    RUBY_TYPED_FREE_IMMEDIATELY
+#endif
+};
 
-/* Allocates Credential instances.
+/* Allocates ChannelCredential instances.
    Provides safe initial defaults for the instance fields. */
-static VALUE grpc_rb_credentials_alloc(VALUE cls) {
-  grpc_rb_credentials *wrapper = ALLOC(grpc_rb_credentials);
+static VALUE grpc_rb_channel_credentials_alloc(VALUE cls) {
+  grpc_rb_channel_credentials *wrapper = ALLOC(grpc_rb_channel_credentials);
   wrapper->wrapped = NULL;
   wrapper->mark = Qnil;
-  return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper);
+  return TypedData_Wrap_Struct(cls, &grpc_rb_channel_credentials_data_type, wrapper);
 }
 
-/* Clones Credentials instances.
-   Gives Credentials a consistent implementation of Ruby's object copy/dup
+/* Clones ChannelCredentials instances.
+   Gives ChannelCredentials a consistent implementation of Ruby's object copy/dup
    protocol. */
-static VALUE grpc_rb_credentials_init_copy(VALUE copy, VALUE orig) {
-  grpc_rb_credentials *orig_cred = NULL;
-  grpc_rb_credentials *copy_cred = NULL;
+static VALUE grpc_rb_channel_credentials_init_copy(VALUE copy, VALUE orig) {
+  grpc_rb_channel_credentials *orig_cred = NULL;
+  grpc_rb_channel_credentials *copy_cred = NULL;
 
   if (copy == orig) {
     return copy;
@@ -116,83 +120,22 @@ static VALUE grpc_rb_credentials_init_copy(VALUE copy, VALUE orig) {
 
   /* Raise an error if orig is not a credentials object or a subclass. */
   if (TYPE(orig) != T_DATA ||
-      RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_credentials_free) {
-    rb_raise(rb_eTypeError, "not a %s", rb_obj_classname(grpc_rb_cCredentials));
+      RDATA(orig)->dfree != (RUBY_DATA_FUNC)grpc_rb_channel_credentials_free) {
+    rb_raise(rb_eTypeError, "not a %s",
+             rb_obj_classname(grpc_rb_cChannelCredentials));
   }
 
-  TypedData_Get_Struct(orig, grpc_rb_credentials,
-                       &grpc_rb_credentials_data_type, orig_cred);
-  TypedData_Get_Struct(copy, grpc_rb_credentials,
-                       &grpc_rb_credentials_data_type, copy_cred);
+  TypedData_Get_Struct(orig, grpc_rb_channel_credentials,
+                       &grpc_rb_channel_credentials_data_type, orig_cred);
+  TypedData_Get_Struct(copy, grpc_rb_channel_credentials,
+                       &grpc_rb_channel_credentials_data_type, copy_cred);
 
   /* use ruby's MEMCPY to make a byte-for-byte copy of the credentials
    * wrapper object. */
-  MEMCPY(copy_cred, orig_cred, grpc_rb_credentials, 1);
+  MEMCPY(copy_cred, orig_cred, grpc_rb_channel_credentials, 1);
   return copy;
 }
 
-/*
-  call-seq:
-    creds = Credentials.default()
-    Creates the default credential instances. */
-static VALUE grpc_rb_default_credentials_create(VALUE cls) {
-  grpc_rb_credentials *wrapper = ALLOC(grpc_rb_credentials);
-  wrapper->wrapped = grpc_google_default_credentials_create();
-  if (wrapper->wrapped == NULL) {
-    rb_raise(rb_eRuntimeError,
-             "could not create default credentials, not sure why");
-    return Qnil;
-  }
-
-  wrapper->mark = Qnil;
-  return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper);
-}
-
-/*
-  call-seq:
-    creds = Credentials.compute_engine()
-    Creates the default credential instances. */
-static VALUE grpc_rb_compute_engine_credentials_create(VALUE cls) {
-  grpc_rb_credentials *wrapper = ALLOC(grpc_rb_credentials);
-  wrapper->wrapped = grpc_google_compute_engine_credentials_create(NULL);
-  if (wrapper->wrapped == NULL) {
-    rb_raise(rb_eRuntimeError,
-             "could not create composite engine credentials, not sure why");
-    return Qnil;
-  }
-
-  wrapper->mark = Qnil;
-  return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper);
-}
-
-/*
-  call-seq:
-    creds1 = ...
-    creds2 = ...
-    creds3 = creds1.add(creds2)
-    Creates the default credential instances. */
-static VALUE grpc_rb_composite_credentials_create(VALUE self, VALUE other) {
-  grpc_rb_credentials *self_wrapper = NULL;
-  grpc_rb_credentials *other_wrapper = NULL;
-  grpc_rb_credentials *wrapper = NULL;
-
-  TypedData_Get_Struct(self, grpc_rb_credentials,
-                       &grpc_rb_credentials_data_type, self_wrapper);
-  TypedData_Get_Struct(other, grpc_rb_credentials,
-                       &grpc_rb_credentials_data_type, other_wrapper);
-  wrapper = ALLOC(grpc_rb_credentials);
-  wrapper->wrapped = grpc_composite_credentials_create(
-      self_wrapper->wrapped, other_wrapper->wrapped, NULL);
-  if (wrapper->wrapped == NULL) {
-    rb_raise(rb_eRuntimeError,
-             "could not create composite credentials, not sure why");
-    return Qnil;
-  }
-
-  wrapper->mark = Qnil;
-  return TypedData_Wrap_Struct(grpc_rb_cCredentials,
-                               &grpc_rb_credentials_data_type, wrapper);
-}
 
 /* The attribute used on the mark object to hold the pem_root_certs. */
 static ID id_pem_root_certs;
@@ -213,12 +156,12 @@ static ID id_pem_cert_chain;
     pem_private_key: (optional) PEM encoding of the client's private key
     pem_cert_chain: (optional) PEM encoding of the client's cert chain
     Initializes Credential instances. */
-static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) {
+static VALUE grpc_rb_channel_credentials_init(int argc, VALUE *argv, VALUE self) {
   VALUE pem_root_certs = Qnil;
   VALUE pem_private_key = Qnil;
   VALUE pem_cert_chain = Qnil;
-  grpc_rb_credentials *wrapper = NULL;
-  grpc_credentials *creds = NULL;
+  grpc_rb_channel_credentials *wrapper = NULL;
+  grpc_channel_credentials *creds = NULL;
   grpc_ssl_pem_key_cert_pair key_cert_pair;
   MEMZERO(&key_cert_pair, grpc_ssl_pem_key_cert_pair, 1);
   /* TODO: Remove mandatory arg when we support default roots. */
@@ -226,8 +169,8 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) {
   rb_scan_args(argc, argv, "12", &pem_root_certs, &pem_private_key,
                &pem_cert_chain);
 
-  TypedData_Get_Struct(self, grpc_rb_credentials,
-                       &grpc_rb_credentials_data_type, wrapper);
+  TypedData_Get_Struct(self, grpc_rb_channel_credentials,
+                       &grpc_rb_channel_credentials_data_type, wrapper);
   if (pem_root_certs == Qnil) {
     rb_raise(rb_eRuntimeError,
              "could not create a credential: nil pem_root_certs");
@@ -256,39 +199,30 @@ static VALUE grpc_rb_credentials_init(int argc, VALUE *argv, VALUE self) {
   return self;
 }
 
-void Init_grpc_credentials() {
-  grpc_rb_cCredentials =
-      rb_define_class_under(grpc_rb_mGrpcCore, "Credentials", rb_cObject);
+void Init_grpc_channel_credentials() {
+  grpc_rb_cChannelCredentials =
+      rb_define_class_under(grpc_rb_mGrpcCore, "ChannelCredentials", rb_cObject);
 
   /* Allocates an object managed by the ruby runtime */
-  rb_define_alloc_func(grpc_rb_cCredentials, grpc_rb_credentials_alloc);
+  rb_define_alloc_func(grpc_rb_cChannelCredentials,
+                       grpc_rb_channel_credentials_alloc);
 
   /* Provides a ruby constructor and support for dup/clone. */
-  rb_define_method(grpc_rb_cCredentials, "initialize", grpc_rb_credentials_init,
-                   -1);
-  rb_define_method(grpc_rb_cCredentials, "initialize_copy",
-                   grpc_rb_credentials_init_copy, 1);
-
-  /* Provide static funcs that create new special instances. */
-  rb_define_singleton_method(grpc_rb_cCredentials, "default",
-                             grpc_rb_default_credentials_create, 0);
-
-  rb_define_singleton_method(grpc_rb_cCredentials, "compute_engine",
-                             grpc_rb_compute_engine_credentials_create, 0);
-
-  /* Provide other methods. */
-  rb_define_method(grpc_rb_cCredentials, "compose",
-                   grpc_rb_composite_credentials_create, 1);
+  rb_define_method(grpc_rb_cChannelCredentials, "initialize",
+                   grpc_rb_channel_credentials_init, -1);
+  rb_define_method(grpc_rb_cChannelCredentials, "initialize_copy",
+                   grpc_rb_channel_credentials_init_copy, 1);
 
   id_pem_cert_chain = rb_intern("__pem_cert_chain");
   id_pem_private_key = rb_intern("__pem_private_key");
   id_pem_root_certs = rb_intern("__pem_root_certs");
 }
 
-/* Gets the wrapped grpc_credentials from the ruby wrapper */
-grpc_credentials *grpc_rb_get_wrapped_credentials(VALUE v) {
-  grpc_rb_credentials *wrapper = NULL;
-  TypedData_Get_Struct(v, grpc_rb_credentials, &grpc_rb_credentials_data_type,
+/* Gets the wrapped grpc_channel_credentials from the ruby wrapper */
+grpc_channel_credentials *grpc_rb_get_wrapped_channel_credentials(VALUE v) {
+  grpc_rb_channel_credentials *wrapper = NULL;
+  TypedData_Get_Struct(v, grpc_rb_channel_credentials,
+                       &grpc_rb_channel_credentials_data_type,
                        wrapper);
   return wrapper->wrapped;
 }
diff --git a/src/ruby/ext/grpc/rb_credentials.h b/src/ruby/ext/grpc/rb_channel_credentials.h
similarity index 91%
rename from src/ruby/ext/grpc/rb_credentials.h
rename to src/ruby/ext/grpc/rb_channel_credentials.h
index 840f7d5f9cfcac3fda595ff53ec7e3589b54c122..15229de93215c124840e37485a8f74607c6e82bc 100644
--- a/src/ruby/ext/grpc/rb_credentials.h
+++ b/src/ruby/ext/grpc/rb_channel_credentials.h
@@ -38,10 +38,10 @@
 
 #include <grpc/grpc_security.h>
 
-/* Initializes the ruby Credentials class. */
-void Init_grpc_credentials();
+/* Initializes the ruby ChannelCredentials class. */
+void Init_grpc_channel_credentials();
 
 /* Gets the wrapped credentials from the ruby wrapper */
-grpc_credentials* grpc_rb_get_wrapped_credentials(VALUE v);
+grpc_channel_credentials* grpc_rb_get_wrapped_channel_credentials(VALUE v);
 
 #endif /* GRPC_RB_CREDENTIALS_H_ */
diff --git a/src/ruby/ext/grpc/rb_completion_queue.c b/src/ruby/ext/grpc/rb_completion_queue.c
index 0bc9eb2a97ae67bd7112dae70c4ea660fd81f4c1..a7de96d71893f61cd5bce0ce636f4df857032566 100644
--- a/src/ruby/ext/grpc/rb_completion_queue.c
+++ b/src/ruby/ext/grpc/rb_completion_queue.c
@@ -121,9 +121,11 @@ static rb_data_type_t grpc_rb_completion_queue_data_type = {
     {GRPC_RB_GC_NOT_MARKED, grpc_rb_completion_queue_destroy,
      GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}},
     NULL, NULL,
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
     /* cannot immediately free because grpc_rb_completion_queue_shutdown_drain
      * calls rb_thread_call_without_gvl. */
-    0
+    0,
+#endif
 };
 
 /* Allocates a completion queue. */
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index 327fd1a4fc1b82afc8f5903d9b7b337a3f251b5c..7c7c2d344044c374b5f4bae352224dac419dc3d0 100644
--- a/src/ruby/ext/grpc/rb_grpc.c
+++ b/src/ruby/ext/grpc/rb_grpc.c
@@ -42,9 +42,9 @@
 #include <grpc/support/time.h>
 #include "rb_call.h"
 #include "rb_channel.h"
+#include "rb_channel_credentials.h"
 #include "rb_completion_queue.h"
 #include "rb_server.h"
-#include "rb_credentials.h"
 #include "rb_server_credentials.h"
 
 static VALUE grpc_rb_cTimeVal = Qnil;
@@ -55,7 +55,10 @@ static rb_data_type_t grpc_rb_timespec_data_type = {
      {NULL, NULL}},
     NULL,
     NULL,
-    RUBY_TYPED_FREE_IMMEDIATELY};
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
+    RUBY_TYPED_FREE_IMMEDIATELY
+#endif
+};
 
 /* Alloc func that blocks allocation of a given object by raising an
  * exception. */
@@ -262,10 +265,20 @@ static void Init_grpc_time_consts() {
   id_tv_nsec = rb_intern("tv_nsec");
 }
 
+/*
+   TODO: find an alternative to ruby_vm_at_exit that is ok in Ruby 2.0 where
+   RUBY_TYPED_FREE_IMMEDIATELY is not defined.
+
+   At the moment, registering a function using ruby_vm_at_exit segfaults in Ruby
+   2.0.  This is not an issue with the gRPC handler.  More likely, this was an
+   in issue with 2.0 that got resolved in 2.1 and has not been backported.
+*/
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
 static void grpc_rb_shutdown(ruby_vm_t *vm) {
   (void)vm;
   grpc_shutdown();
 }
+#endif
 
 /* Initialize the GRPC module structs */
 
@@ -285,7 +298,12 @@ VALUE sym_metadata = Qundef;
 
 void Init_grpc() {
   grpc_init();
+
+/* TODO: find alternative to ruby_vm_at_exit that is ok in Ruby 2.0 */
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
   ruby_vm_at_exit(grpc_rb_shutdown);
+#endif
+
   grpc_rb_mGRPC = rb_define_module("GRPC");
   grpc_rb_mGrpcCore = rb_define_module_under(grpc_rb_mGRPC, "Core");
   grpc_rb_sNewServerRpc =
@@ -300,7 +318,7 @@ void Init_grpc() {
   Init_grpc_channel();
   Init_grpc_completion_queue();
   Init_grpc_call();
-  Init_grpc_credentials();
+  Init_grpc_channel_credentials();
   Init_grpc_server();
   Init_grpc_server_credentials();
   Init_grpc_status_codes();
diff --git a/src/ruby/ext/grpc/rb_server.c b/src/ruby/ext/grpc/rb_server.c
index 446965886968b3779e919f14cef529d13140a4ab..ebdd7e1a346a2b49374ef533e5f4b6872d2a1d0b 100644
--- a/src/ruby/ext/grpc/rb_server.c
+++ b/src/ruby/ext/grpc/rb_server.c
@@ -101,11 +101,14 @@ static const rb_data_type_t grpc_rb_server_data_type = {
      {NULL, NULL}},
     NULL,
     NULL,
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
     /* It is unsafe to specify RUBY_TYPED_FREE_IMMEDIATELY because the free function would block
      * and we might want to unlock GVL
      * TODO(yugui) Unlock GVL?
      */
-    0};
+    0,
+#endif
+};
 
 /* Allocates grpc_rb_server instances. */
 static VALUE grpc_rb_server_alloc(VALUE cls) {
diff --git a/src/ruby/ext/grpc/rb_server_credentials.c b/src/ruby/ext/grpc/rb_server_credentials.c
index ea4d0d864ecf7c3233eae43b4ce47bfe155342f4..de57585e0baecef5185f8128eee3a46b34e5cccd 100644
--- a/src/ruby/ext/grpc/rb_server_credentials.c
+++ b/src/ruby/ext/grpc/rb_server_credentials.c
@@ -91,7 +91,9 @@ static const rb_data_type_t grpc_rb_server_credentials_data_type = {
     {grpc_rb_server_credentials_mark, grpc_rb_server_credentials_free,
      GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}},
     NULL, NULL,
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
     RUBY_TYPED_FREE_IMMEDIATELY
+#endif
 };
 
 /* Allocates ServerCredential instances.
diff --git a/src/ruby/lib/grpc/generic/active_call.rb b/src/ruby/lib/grpc/generic/active_call.rb
index d9cb924735610396ac610d50a4fd451d0d4743a4..e80d24edc9b487993c368ee693d61b8685d91c64 100644
--- a/src/ruby/lib/grpc/generic/active_call.rb
+++ b/src/ruby/lib/grpc/generic/active_call.rb
@@ -199,11 +199,7 @@ module GRPC
     # marshalled.
     def remote_send(req, marshalled = false)
       GRPC.logger.debug("sending #{req}, marshalled? #{marshalled}")
-      if marshalled
-        payload = req
-      else
-        payload = @marshal.call(req)
-      end
+      payload = marshalled ? req : @marshal.call(req)
       @call.run_batch(@cq, self, INFINITE_FUTURE, SEND_MESSAGE => payload)
     end
 
@@ -417,7 +413,9 @@ module GRPC
     # @return [Enumerator, nil] a response Enumerator
     def bidi_streamer(requests, **kw, &blk)
       start_call(**kw) unless @started
-      bd = BidiCall.new(@call, @cq, @marshal, @unmarshal)
+      bd = BidiCall.new(@call, @cq, @marshal, @unmarshal,
+                        metadata_tag: @metadata_tag)
+      @metadata_tag = nil  # run_on_client ensures metadata is read
       bd.run_on_client(requests, @op_notifier, &blk)
     end
 
diff --git a/src/ruby/lib/grpc/generic/bidi_call.rb b/src/ruby/lib/grpc/generic/bidi_call.rb
index 9dbbb74caff191cce3fcf31cdf52d1b949f4a0be..6b9b7856933cb94dd86144b4f80ad9cc0b904f43 100644
--- a/src/ruby/lib/grpc/generic/bidi_call.rb
+++ b/src/ruby/lib/grpc/generic/bidi_call.rb
@@ -56,7 +56,8 @@ module GRPC
     #          the call
     # @param marshal [Function] f(obj)->string that marshal requests
     # @param unmarshal [Function] f(string)->obj that unmarshals responses
-    def initialize(call, q, marshal, unmarshal)
+    # @param metadata_tag [Object] tag object used to collect metadata
+    def initialize(call, q, marshal, unmarshal, metadata_tag: nil)
       fail(ArgumentError, 'not a call') unless call.is_a? Core::Call
       unless q.is_a? Core::CompletionQueue
         fail(ArgumentError, 'not a CompletionQueue')
@@ -67,6 +68,7 @@ module GRPC
       @op_notifier = nil  # signals completion on clients
       @readq = Queue.new
       @unmarshal = unmarshal
+      @metadata_tag = metadata_tag
     end
 
     # Begins orchestration of the Bidi stream for a client sending requests.
@@ -113,6 +115,18 @@ module GRPC
       @op_notifier.notify(self)
     end
 
+    # performs a read using @call.run_batch, ensures metadata is set up
+    def read_using_run_batch
+      ops = { RECV_MESSAGE => nil }
+      ops[RECV_INITIAL_METADATA] = nil unless @metadata_tag.nil?
+      batch_result = @call.run_batch(@cq, self, INFINITE_FUTURE, ops)
+      unless @metadata_tag.nil?
+        @call.metadata = batch_result.metadata
+        @metadata_tag = nil
+      end
+      batch_result
+    end
+
     # each_queued_msg yields each message on this instances readq
     #
     # - messages are added to the readq by #read_loop
@@ -169,9 +183,7 @@ module GRPC
           loop do
             GRPC.logger.debug("bidi-read-loop: #{count}")
             count += 1
-            # TODO: ensure metadata is read if available, currently it's not
-            batch_result = @call.run_batch(@cq, read_tag, INFINITE_FUTURE,
-                                           RECV_MESSAGE => nil)
+            batch_result = read_using_run_batch
 
             # handle the next message
             if batch_result.message.nil?
diff --git a/src/ruby/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb
index b8e33ad295ab3c6e556446854346895f2df9189a..90aaa026ec46804d6964bdce990ae9b6bb3bb081 100644
--- a/src/ruby/lib/grpc/generic/client_stub.rb
+++ b/src/ruby/lib/grpc/generic/client_stub.rb
@@ -51,7 +51,9 @@ module GRPC
       end
       kw['grpc.primary_user_agent'] = "grpc-ruby/#{VERSION}"
       return Core::Channel.new(host, kw) if creds.nil?
-      fail(TypeError, '!Credentials') unless creds.is_a?(Core::Credentials)
+      unless creds.is_a?(Core::ChannelCredentials)
+        fail(TypeError, '!ChannelCredentials')
+      end
       Core::Channel.new(host, kw, creds)
     end
 
@@ -106,7 +108,7 @@ module GRPC
     # @param q [Core::CompletionQueue] used to wait for events
     # @param channel_override [Core::Channel] a pre-created channel
     # @param timeout [Number] the default timeout to use in requests
-    # @param creds [Core::Credentials] the channel
+    # @param creds [Core::ChannelCredentials] the channel credentials
     # @param update_metadata a func that updates metadata as described above
     # @param kw [KeywordArgs]the channel arguments
     def initialize(host, q,
diff --git a/src/ruby/lib/grpc/generic/rpc_server.rb b/src/ruby/lib/grpc/generic/rpc_server.rb
index 228c500672b859499596e8e769e0f40929ba71df..0e318bd53b8fb5e693a40af13cc8d35f1783ed79 100644
--- a/src/ruby/lib/grpc/generic/rpc_server.rb
+++ b/src/ruby/lib/grpc/generic/rpc_server.rb
@@ -418,11 +418,11 @@ module GRPC
           an_rpc = @server.request_call(@cq, loop_tag, INFINITE_FUTURE)
           break if (!an_rpc.nil?) && an_rpc.call.nil?
 
-          c = new_active_server_call(an_rpc)
-          unless c.nil?
-            mth = an_rpc.method.to_sym
-            @pool.schedule(c) do |call|
-              rpc_descs[mth].run_server_method(call, rpc_handlers[mth])
+          active_call = new_active_server_call(an_rpc)
+          unless active_call.nil?
+            @pool.schedule(active_call) do |ac|
+              c, mth = ac
+              rpc_descs[mth].run_server_method(c, rpc_handlers[mth])
             end
           end
         rescue Core::CallError, RuntimeError => e
@@ -442,6 +442,7 @@ module GRPC
       # allow the metadata to be accessed from the call
       handle_call_tag = Object.new
       an_rpc.call.metadata = an_rpc.metadata  # attaches md to call for handlers
+      GRPC.logger.debug("call md is #{an_rpc.metadata}")
       connect_md = nil
       unless @connect_md_proc.nil?
         connect_md = @connect_md_proc.call(an_rpc.method, an_rpc.metadata)
@@ -454,9 +455,11 @@ module GRPC
       # Create the ActiveCall
       GRPC.logger.info("deadline is #{an_rpc.deadline}; (now=#{Time.now})")
       rpc_desc = rpc_descs[an_rpc.method.to_sym]
-      ActiveCall.new(an_rpc.call, @cq,
-                     rpc_desc.marshal_proc, rpc_desc.unmarshal_proc(:input),
-                     an_rpc.deadline)
+      c = ActiveCall.new(an_rpc.call, @cq,
+                         rpc_desc.marshal_proc, rpc_desc.unmarshal_proc(:input),
+                         an_rpc.deadline)
+      mth = an_rpc.method.to_sym
+      [c, mth]
     end
 
     protected
diff --git a/src/ruby/pb/test/client.rb b/src/ruby/pb/test/client.rb
index 1388685734a3d51635992c6cfe3fc7aba39f02cd..30550d6cc0a7b473c4715bd0a3357b4c6385d5cf 100755
--- a/src/ruby/pb/test/client.rb
+++ b/src/ruby/pb/test/client.rb
@@ -46,6 +46,7 @@ $LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
 $LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
 
 require 'optparse'
+require 'logger'
 
 require 'grpc'
 require 'googleauth'
@@ -59,6 +60,22 @@ require 'signet/ssl_config'
 
 AUTH_ENV = Google::Auth::CredentialsLoader::ENV_VAR
 
+# RubyLogger defines a logger for gRPC based on the standard ruby logger.
+module RubyLogger
+  def logger
+    LOGGER
+  end
+
+  LOGGER = Logger.new(STDOUT)
+  LOGGER.level = Logger::INFO
+end
+
+# GRPC is the general RPC module
+module GRPC
+  # Inject the noop #logger if no module-level logger method has been injected.
+  extend RubyLogger
+end
+
 # AssertionError is use to indicate interop test failures.
 class AssertionError < RuntimeError; end
 
@@ -86,13 +103,13 @@ end
 # creates SSL Credentials from the test certificates.
 def test_creds
   certs = load_test_certs
-  GRPC::Core::Credentials.new(certs[0])
+  GRPC::Core::ChannelCredentials.new(certs[0])
 end
 
 # creates SSL Credentials from the production certificates.
 def prod_creds
   cert_text = load_prod_cert
-  GRPC::Core::Credentials.new(cert_text)
+  GRPC::Core::ChannelCredentials.new(cert_text)
 end
 
 # creates the SSL Credentials.
diff --git a/src/ruby/pb/test/server.rb b/src/ruby/pb/test/server.rb
index 25c1b1e9e64e7f06a5a2f60e8f6c93f61cfbe2d6..67877a191fc96505f5040cd826568235921a439a 100755
--- a/src/ruby/pb/test/server.rb
+++ b/src/ruby/pb/test/server.rb
@@ -45,6 +45,7 @@ $LOAD_PATH.unshift(pb_dir) unless $LOAD_PATH.include?(pb_dir)
 $LOAD_PATH.unshift(this_dir) unless $LOAD_PATH.include?(this_dir)
 
 require 'forwardable'
+require 'logger'
 require 'optparse'
 
 require 'grpc'
@@ -53,6 +54,60 @@ require 'test/proto/empty'
 require 'test/proto/messages'
 require 'test/proto/test_services'
 
+# DebugIsTruncated extends the default Logger to truncate debug messages
+class DebugIsTruncated < Logger
+  def debug(s)
+    super(truncate(s, 1024))
+  end
+
+  # Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>:
+  #
+  #   'Once upon a time in a world far far away'.truncate(27)
+  #   # => "Once upon a time in a wo..."
+  #
+  # Pass a string or regexp <tt>:separator</tt> to truncate +text+ at a natural break:
+  #
+  #   'Once upon a time in a world far far away'.truncate(27, separator: ' ')
+  #   # => "Once upon a time in a..."
+  #
+  #   'Once upon a time in a world far far away'.truncate(27, separator: /\s/)
+  #   # => "Once upon a time in a..."
+  #
+  # The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
+  # for a total length not exceeding <tt>length</tt>:
+  #
+  #   'And they found that many people were sleeping better.'.truncate(25, omission: '... (continued)')
+  #   # => "And they f... (continued)"
+  def truncate(s, truncate_at, options = {})
+    return s unless s.length > truncate_at
+    omission = options[:omission] || '...'
+    with_extra_room = truncate_at - omission.length
+    stop = \
+      if options[:separator]
+        rindex(options[:separator], with_extra_room) || with_extra_room
+      else
+        with_extra_room
+      end
+    "#{s[0, stop]}#{omission}"
+  end
+end
+
+# RubyLogger defines a logger for gRPC based on the standard ruby logger.
+module RubyLogger
+  def logger
+    LOGGER
+  end
+
+  LOGGER = DebugIsTruncated.new(STDOUT)
+  LOGGER.level = Logger::WARN
+end
+
+# GRPC is the general RPC module
+module GRPC
+  # Inject the noop #logger if no module-level logger method has been injected.
+  extend RubyLogger
+end
+
 # loads the certificates by the test server.
 def load_test_certs
   this_dir = File.expand_path(File.dirname(__FILE__))
@@ -113,7 +168,7 @@ class TestTarget < Grpc::Testing::TestService::Service
 
   def streaming_input_call(call)
     sizes = call.each_remote_read.map { |x| x.payload.body.length }
-    sum = sizes.inject { |s, x| s + x }
+    sum = sizes.inject(0) { |s, x| s + x }
     StreamingInputCallResponse.new(aggregated_payload_size: sum)
   end
 
diff --git a/src/ruby/spec/credentials_spec.rb b/src/ruby/spec/channel_credentials_spec.rb
similarity index 78%
rename from src/ruby/spec/credentials_spec.rb
rename to src/ruby/spec/channel_credentials_spec.rb
index b02219dfdbbf83f39aba2c52886e737baccd5b68..b2bdf7032e0882745a28d91f9491cf924da12128 100644
--- a/src/ruby/spec/credentials_spec.rb
+++ b/src/ruby/spec/channel_credentials_spec.rb
@@ -29,8 +29,8 @@
 
 require 'grpc'
 
-describe GRPC::Core::Credentials do
-  Credentials = GRPC::Core::Credentials
+describe GRPC::Core::ChannelCredentials do
+  ChannelCredentials = GRPC::Core::ChannelCredentials
 
   def load_test_certs
     test_root = File.join(File.dirname(__FILE__), 'testdata')
@@ -40,32 +40,24 @@ describe GRPC::Core::Credentials do
 
   describe '#new' do
     it 'can be constructed with fake inputs' do
-      expect { Credentials.new('root_certs', 'key', 'cert') }.not_to raise_error
+      blk = proc  { ChannelCredentials.new('root_certs', 'key', 'cert') }
+      expect(&blk).not_to raise_error
     end
 
     it 'it can be constructed using specific test certificates' do
       certs = load_test_certs
-      expect { Credentials.new(*certs) }.not_to raise_error
+      expect { ChannelCredentials.new(*certs) }.not_to raise_error
     end
 
     it 'can be constructed with server roots certs only' do
       root_cert, _, _ = load_test_certs
-      expect { Credentials.new(root_cert) }.not_to raise_error
+      expect { ChannelCredentials.new(root_cert) }.not_to raise_error
     end
 
     it 'cannot be constructed with a nil server roots' do
       _, client_key, client_chain = load_test_certs
-      blk = proc { Credentials.new(nil, client_key, client_chain) }
+      blk = proc { ChannelCredentials.new(nil, client_key, client_chain) }
       expect(&blk).to raise_error
     end
   end
-
-  describe '#compose' do
-    it 'cannot be completed OK with 2 SSL creds' do
-      certs = load_test_certs
-      cred1 = Credentials.new(*certs)
-      cred2 = Credentials.new(*certs)
-      expect { cred1.compose(cred2) }.to raise_error
-    end
-  end
 end
diff --git a/src/ruby/spec/channel_spec.rb b/src/ruby/spec/channel_spec.rb
index 25cefcdfb766b15fa5e39a53bb8c27556fc75e90..b4d2b94a819be73bafab7587a4f9d7445d0d76c5 100644
--- a/src/ruby/spec/channel_spec.rb
+++ b/src/ruby/spec/channel_spec.rb
@@ -40,7 +40,7 @@ describe GRPC::Core::Channel do
   let(:cq) { GRPC::Core::CompletionQueue.new }
 
   def create_test_cert
-    GRPC::Core::Credentials.new(load_test_certs[0])
+    GRPC::Core::ChannelCredentials.new(load_test_certs[0])
   end
 
   shared_examples '#new' do
diff --git a/src/ruby/spec/client_server_spec.rb b/src/ruby/spec/client_server_spec.rb
index ad0fb26896a8c1644854a076d3e0562a1f8e7e70..734f176e941a6f5e153c02eb2b4e3f1906c94d72 100644
--- a/src/ruby/spec/client_server_spec.rb
+++ b/src/ruby/spec/client_server_spec.rb
@@ -431,7 +431,7 @@ describe 'the secure http client/server' do
     @server.start
     args = { Channel::SSL_TARGET => 'foo.test.google.fr' }
     @ch = Channel.new("0.0.0.0:#{server_port}", args,
-                      GRPC::Core::Credentials.new(certs[0], nil, nil))
+                      GRPC::Core::ChannelCredentials.new(certs[0], nil, nil))
   end
 
   after(:example) do
diff --git a/src/ruby/spec/generic/client_stub_spec.rb b/src/ruby/spec/generic/client_stub_spec.rb
index c5173aee1d59c62c2d2a462f3596abf4aedee0cf..da5bc6c9e51b7647351a68ac477ea502dabcb503 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -113,7 +113,7 @@ describe 'ClientStub' do
         opts = {
           GRPC::Core::Channel::SSL_TARGET => 'foo.test.google.fr',
           a_channel_arg: 'an_arg',
-          creds: GRPC::Core::Credentials.new(certs[0], nil, nil)
+          creds: GRPC::Core::ChannelCredentials.new(certs[0], nil, nil)
         }
         GRPC::ClientStub.new(fake_host, @cq, **opts)
       end
diff --git a/src/ruby/spec/pb/health/checker_spec.rb b/src/ruby/spec/pb/health/checker_spec.rb
index 9bc82638c75fd3091e655b531035ca20234951cd..322566b7842fe316a446fd228dd9b735587a9fcb 100644
--- a/src/ruby/spec/pb/health/checker_spec.rb
+++ b/src/ruby/spec/pb/health/checker_spec.rb
@@ -31,6 +31,7 @@ require 'grpc'
 require 'grpc/health/v1alpha/health'
 require 'grpc/health/checker'
 require 'open3'
+require 'tmpdir'
 
 def can_run_codegen_check
   system('which grpc_ruby_plugin') && system('which protoc')
diff --git a/src/ruby/spec/testdata/server1.pem b/src/ruby/spec/testdata/server1.pem
index 8e582e571f643ca3fb6042a786c709a53f5afcf3..f3d43fcc5beadd98542abdaa32acfb555b807559 100755
--- a/src/ruby/spec/testdata/server1.pem
+++ b/src/ruby/spec/testdata/server1.pem
@@ -1,16 +1,16 @@
 -----BEGIN CERTIFICATE-----
-MIICmzCCAgSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADBWMQswCQYDVQQGEwJBVTET
-MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ
-dHkgTHRkMQ8wDQYDVQQDDAZ0ZXN0Y2EwHhcNMTQwNzIyMDYwMDU3WhcNMjQwNzE5
-MDYwMDU3WjBkMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
-BAcTB0NoaWNhZ28xFDASBgNVBAoTC0dvb2dsZSBJbmMuMRowGAYDVQQDFBEqLnRl
-c3QuZ29vZ2xlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA4cMVJygs
-JUmlgMMzgdi0h1XoCR7+ww1pop04OMMyy7H/i0PJ2W6Y35+b4CM8QrkYeEafUGDO
-RYX6yV/cHGGsD/x02ye6ey1UDtkGAD/mpDEx8YCrjAc1Vfvt8Fk6Cn1WVIxV/J30
-3xjBsFgByQ55RBp1OLZfVLo6AleBDSbcxaECAwEAAaNrMGkwCQYDVR0TBAIwADAL
-BgNVHQ8EBAMCBeAwTwYDVR0RBEgwRoIQKi50ZXN0Lmdvb2dsZS5mcoIYd2F0ZXJ6
-b29pLnRlc3QuZ29vZ2xlLmJlghIqLnRlc3QueW91dHViZS5jb22HBMCoAQMwDQYJ
-KoZIhvcNAQEFBQADgYEAM2Ii0LgTGbJ1j4oqX9bxVcxm+/R5Yf8oi0aZqTJlnLYS
-wXcBykxTx181s7WyfJ49WwrYXo78zTDAnf1ma0fPq3e4mpspvyndLh1a+OarHa1e
-aT0DIIYk7qeEa1YcVljx2KyLd0r1BBAfrwyGaEPVeJQVYWaOJRU2we/KD4ojf9s=
+MIICnDCCAgWgAwIBAgIBBzANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJBVTET
+MBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lkZ2l0cyBQ
+dHkgTHRkMQ8wDQYDVQQDEwZ0ZXN0Y2EwHhcNMTUxMTA0MDIyMDI0WhcNMjUxMTAx
+MDIyMDI0WjBlMQswCQYDVQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNV
+BAcTB0NoaWNhZ28xFTATBgNVBAoTDEV4YW1wbGUsIENvLjEaMBgGA1UEAxQRKi50
+ZXN0Lmdvb2dsZS5jb20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOHDFSco
+LCVJpYDDM4HYtIdV6Ake/sMNaaKdODjDMsux/4tDydlumN+fm+AjPEK5GHhGn1Bg
+zkWF+slf3BxhrA/8dNsnunstVA7ZBgA/5qQxMfGAq4wHNVX77fBZOgp9VlSMVfyd
+9N8YwbBYAckOeUQadTi2X1S6OgJXgQ0m3MWhAgMBAAGjazBpMAkGA1UdEwQCMAAw
+CwYDVR0PBAQDAgXgME8GA1UdEQRIMEaCECoudGVzdC5nb29nbGUuZnKCGHdhdGVy
+em9vaS50ZXN0Lmdvb2dsZS5iZYISKi50ZXN0LnlvdXR1YmUuY29thwTAqAEDMA0G
+CSqGSIb3DQEBCwUAA4GBAJFXVifQNub1LUP4JlnX5lXNlo8FxZ2a12AFQs+bzoJ6
+hM044EDjqyxUqSbVePK0ni3w1fHQB5rY9yYC5f8G7aqqTY1QOhoUk8ZTSTRpnkTh
+y4jjdvTZeLDVBlueZUTDRmy2feY5aZIU18vFDK08dTG0A87pppuv1LNIR3loveU8
 -----END CERTIFICATE-----
diff --git a/templates/binding.gyp.template b/templates/binding.gyp.template
index 52070cf6e9e6c0ac450c95321df813eca0e125f4..be80750eb7f67877fe790a08da034e608bdf5964 100644
--- a/templates/binding.gyp.template
+++ b/templates/binding.gyp.template
@@ -89,8 +89,9 @@
       ]
     },
     'targets': [
+      % for module in node_modules:
       % for lib in libs:
-      % if lib.name == 'gpr' or lib.name == 'grpc':
+      % if lib.name in module.transitive_deps:
       {
         'target_name': '${lib.name}',
         'product_prefix': 'lib',
@@ -142,22 +143,18 @@
             }
           }]
         ],
-        "target_name": "grpc_node",
+        "target_name": "${module.name}",
         "sources": [
-          "src/node/ext/byte_buffer.cc",
-          "src/node/ext/call.cc",
-          "src/node/ext/call_credentials.cc",
-          "src/node/ext/channel.cc",
-          "src/node/ext/channel_credentials.cc",
-          "src/node/ext/completion_queue_async_worker.cc",
-          "src/node/ext/node_grpc.cc",
-          "src/node/ext/server.cc",
-          "src/node/ext/server_credentials.cc",
-          "src/node/ext/timeval.cc"
+          % for source in module.src:
+          "${source}",
+          % endfor
         ],
         "dependencies": [
-          "grpc"
+          % for dep in getattr(module, 'deps', []):
+          "${dep}",
+          % endfor
         ]
-      }
+      },
+      % endfor
     ]
   }
diff --git a/test/core/client_config/lb_policies_test.c b/test/core/client_config/lb_policies_test.c
index 8498e1d82702531548b3189cc6ba03a8b9f23985..cd9aa942e2f1011c9d3221849a7d46cef7d7acf7 100644
--- a/test/core/client_config/lb_policies_test.c
+++ b/test/core/client_config/lb_policies_test.c
@@ -303,8 +303,8 @@ int *perform_request(servers_fixture *f, grpc_channel *client,
 
     s_idx = -1;
     while ((ev = grpc_completion_queue_next(
-                f->cq, n_millis_time(s_idx == -1 ? 3000 : 200), NULL)).type !=
-           GRPC_QUEUE_TIMEOUT) {
+                f->cq, GRPC_TIMEOUT_SECONDS_TO_DEADLINE(1), NULL))
+               .type != GRPC_QUEUE_TIMEOUT) {
       GPR_ASSERT(ev.type == GRPC_OP_COMPLETE);
       read_tag = ((int)(gpr_intptr)ev.tag);
       gpr_log(GPR_DEBUG, "EVENT: success:%d, type:%d, tag:%d iter:%d",
@@ -315,6 +315,7 @@ int *perform_request(servers_fixture *f, grpc_channel *client,
         s_idx = read_tag - 1000;
         s_valid[s_idx] = 1;
         connection_sequence[iter_num] = s_idx;
+        break;
       } else if (read_tag == 1) {
         gpr_log(GPR_DEBUG, "client timed out");
         GPR_ASSERT(ev.success);
@@ -453,6 +454,8 @@ void run_spec(const test_spec *spec) {
   int *actual_connection_sequence;
   request_data rdata;
   servers_fixture *f;
+  grpc_channel_args args;
+  grpc_arg arg;
   rdata.call_details =
       gpr_malloc(sizeof(grpc_call_details) * spec->num_servers);
   f = setup_servers("127.0.0.1", &rdata, spec->num_servers);
@@ -462,7 +465,14 @@ void run_spec(const test_spec *spec) {
                                           f->num_servers, ",", NULL);
   gpr_asprintf(&client_hostport, "ipv4:%s?lb_policy=round_robin",
                servers_hostports_str);
-  client = grpc_insecure_channel_create(client_hostport, NULL, NULL);
+
+  arg.type = GRPC_ARG_INTEGER;
+  arg.key = "grpc.testing.fixed_reconnect_backoff";
+  arg.value.integer = 100;
+  args.num_args = 1;
+  args.args = &arg;
+
+  client = grpc_insecure_channel_create(client_hostport, &args, NULL);
 
   gpr_log(GPR_INFO, "Testing '%s' with servers=%s client=%s", spec->description,
           servers_hostports_str, client_hostport);
diff --git a/test/core/end2end/data/server1_cert.c b/test/core/end2end/data/server1_cert.c
index d31f2e2d0ed5fd3f4ff84624a796ebf68863ad85..82d65cf551a52b237fdfabc9d6ec51d5ea7f0ef2 100644
--- a/test/core/end2end/data/server1_cert.c
+++ b/test/core/end2end/data/server1_cert.c
@@ -34,82 +34,82 @@
 const char test_server1_cert[] = {
     0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x42, 0x45, 0x47, 0x49, 0x4e, 0x20, 0x43,
     0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
-    0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6d, 0x7a, 0x43, 0x43,
-    0x41, 0x67, 0x53, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42,
-    0x41, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47,
-    0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x55, 0x46, 0x41, 0x44, 0x42, 0x57,
+    0x2d, 0x2d, 0x2d, 0x0a, 0x4d, 0x49, 0x49, 0x43, 0x6e, 0x44, 0x43, 0x43,
+    0x41, 0x67, 0x57, 0x67, 0x41, 0x77, 0x49, 0x42, 0x41, 0x67, 0x49, 0x42,
+    0x42, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69, 0x47,
+    0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x73, 0x46, 0x41, 0x44, 0x42, 0x57,
     0x4d, 0x51, 0x73, 0x77, 0x43, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47,
     0x45, 0x77, 0x4a, 0x42, 0x56, 0x54, 0x45, 0x54, 0x0a, 0x4d, 0x42, 0x45,
-    0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x41, 0x77, 0x4b, 0x55, 0x32, 0x39,
+    0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x42, 0x4d, 0x4b, 0x55, 0x32, 0x39,
     0x74, 0x5a, 0x53, 0x31, 0x54, 0x64, 0x47, 0x46, 0x30, 0x5a, 0x54, 0x45,
-    0x68, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x67, 0x77,
+    0x68, 0x4d, 0x42, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43, 0x68, 0x4d,
     0x59, 0x53, 0x57, 0x35, 0x30, 0x5a, 0x58, 0x4a, 0x75, 0x5a, 0x58, 0x51,
     0x67, 0x56, 0x32, 0x6c, 0x6b, 0x5a, 0x32, 0x6c, 0x30, 0x63, 0x79, 0x42,
     0x51, 0x0a, 0x64, 0x48, 0x6b, 0x67, 0x54, 0x48, 0x52, 0x6b, 0x4d, 0x51,
-    0x38, 0x77, 0x44, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x44, 0x41,
+    0x38, 0x77, 0x44, 0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x45, 0x77,
     0x5a, 0x30, 0x5a, 0x58, 0x4e, 0x30, 0x59, 0x32, 0x45, 0x77, 0x48, 0x68,
-    0x63, 0x4e, 0x4d, 0x54, 0x51, 0x77, 0x4e, 0x7a, 0x49, 0x79, 0x4d, 0x44,
-    0x59, 0x77, 0x4d, 0x44, 0x55, 0x33, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a,
-    0x51, 0x77, 0x4e, 0x7a, 0x45, 0x35, 0x0a, 0x4d, 0x44, 0x59, 0x77, 0x4d,
-    0x44, 0x55, 0x33, 0x57, 0x6a, 0x42, 0x6b, 0x4d, 0x51, 0x73, 0x77, 0x43,
+    0x63, 0x4e, 0x4d, 0x54, 0x55, 0x78, 0x4d, 0x54, 0x41, 0x30, 0x4d, 0x44,
+    0x49, 0x79, 0x4d, 0x44, 0x49, 0x30, 0x57, 0x68, 0x63, 0x4e, 0x4d, 0x6a,
+    0x55, 0x78, 0x4d, 0x54, 0x41, 0x78, 0x0a, 0x4d, 0x44, 0x49, 0x79, 0x4d,
+    0x44, 0x49, 0x30, 0x57, 0x6a, 0x42, 0x6c, 0x4d, 0x51, 0x73, 0x77, 0x43,
     0x51, 0x59, 0x44, 0x56, 0x51, 0x51, 0x47, 0x45, 0x77, 0x4a, 0x56, 0x55,
     0x7a, 0x45, 0x52, 0x4d, 0x41, 0x38, 0x47, 0x41, 0x31, 0x55, 0x45, 0x43,
     0x42, 0x4d, 0x49, 0x53, 0x57, 0x78, 0x73, 0x61, 0x57, 0x35, 0x76, 0x61,
     0x58, 0x4d, 0x78, 0x45, 0x44, 0x41, 0x4f, 0x42, 0x67, 0x4e, 0x56, 0x0a,
     0x42, 0x41, 0x63, 0x54, 0x42, 0x30, 0x4e, 0x6f, 0x61, 0x57, 0x4e, 0x68,
-    0x5a, 0x32, 0x38, 0x78, 0x46, 0x44, 0x41, 0x53, 0x42, 0x67, 0x4e, 0x56,
-    0x42, 0x41, 0x6f, 0x54, 0x43, 0x30, 0x64, 0x76, 0x62, 0x32, 0x64, 0x73,
-    0x5a, 0x53, 0x42, 0x4a, 0x62, 0x6d, 0x4d, 0x75, 0x4d, 0x52, 0x6f, 0x77,
-    0x47, 0x41, 0x59, 0x44, 0x56, 0x51, 0x51, 0x44, 0x46, 0x42, 0x45, 0x71,
-    0x4c, 0x6e, 0x52, 0x6c, 0x0a, 0x63, 0x33, 0x51, 0x75, 0x5a, 0x32, 0x39,
-    0x76, 0x5a, 0x32, 0x78, 0x6c, 0x4c, 0x6d, 0x4e, 0x76, 0x62, 0x54, 0x43,
-    0x42, 0x6e, 0x7a, 0x41, 0x4e, 0x42, 0x67, 0x6b, 0x71, 0x68, 0x6b, 0x69,
-    0x47, 0x39, 0x77, 0x30, 0x42, 0x41, 0x51, 0x45, 0x46, 0x41, 0x41, 0x4f,
-    0x42, 0x6a, 0x51, 0x41, 0x77, 0x67, 0x59, 0x6b, 0x43, 0x67, 0x59, 0x45,
-    0x41, 0x34, 0x63, 0x4d, 0x56, 0x4a, 0x79, 0x67, 0x73, 0x0a, 0x4a, 0x55,
-    0x6d, 0x6c, 0x67, 0x4d, 0x4d, 0x7a, 0x67, 0x64, 0x69, 0x30, 0x68, 0x31,
-    0x58, 0x6f, 0x43, 0x52, 0x37, 0x2b, 0x77, 0x77, 0x31, 0x70, 0x6f, 0x70,
-    0x30, 0x34, 0x4f, 0x4d, 0x4d, 0x79, 0x79, 0x37, 0x48, 0x2f, 0x69, 0x30,
-    0x50, 0x4a, 0x32, 0x57, 0x36, 0x59, 0x33, 0x35, 0x2b, 0x62, 0x34, 0x43,
-    0x4d, 0x38, 0x51, 0x72, 0x6b, 0x59, 0x65, 0x45, 0x61, 0x66, 0x55, 0x47,
-    0x44, 0x4f, 0x0a, 0x52, 0x59, 0x58, 0x36, 0x79, 0x56, 0x2f, 0x63, 0x48,
-    0x47, 0x47, 0x73, 0x44, 0x2f, 0x78, 0x30, 0x32, 0x79, 0x65, 0x36, 0x65,
-    0x79, 0x31, 0x55, 0x44, 0x74, 0x6b, 0x47, 0x41, 0x44, 0x2f, 0x6d, 0x70,
-    0x44, 0x45, 0x78, 0x38, 0x59, 0x43, 0x72, 0x6a, 0x41, 0x63, 0x31, 0x56,
-    0x66, 0x76, 0x74, 0x38, 0x46, 0x6b, 0x36, 0x43, 0x6e, 0x31, 0x57, 0x56,
-    0x49, 0x78, 0x56, 0x2f, 0x4a, 0x33, 0x30, 0x0a, 0x33, 0x78, 0x6a, 0x42,
-    0x73, 0x46, 0x67, 0x42, 0x79, 0x51, 0x35, 0x35, 0x52, 0x42, 0x70, 0x31,
-    0x4f, 0x4c, 0x5a, 0x66, 0x56, 0x4c, 0x6f, 0x36, 0x41, 0x6c, 0x65, 0x42,
-    0x44, 0x53, 0x62, 0x63, 0x78, 0x61, 0x45, 0x43, 0x41, 0x77, 0x45, 0x41,
-    0x41, 0x61, 0x4e, 0x72, 0x4d, 0x47, 0x6b, 0x77, 0x43, 0x51, 0x59, 0x44,
-    0x56, 0x52, 0x30, 0x54, 0x42, 0x41, 0x49, 0x77, 0x41, 0x44, 0x41, 0x4c,
-    0x0a, 0x42, 0x67, 0x4e, 0x56, 0x48, 0x51, 0x38, 0x45, 0x42, 0x41, 0x4d,
-    0x43, 0x42, 0x65, 0x41, 0x77, 0x54, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30,
-    0x52, 0x42, 0x45, 0x67, 0x77, 0x52, 0x6f, 0x49, 0x51, 0x4b, 0x69, 0x35,
-    0x30, 0x5a, 0x58, 0x4e, 0x30, 0x4c, 0x6d, 0x64, 0x76, 0x62, 0x32, 0x64,
-    0x73, 0x5a, 0x53, 0x35, 0x6d, 0x63, 0x6f, 0x49, 0x59, 0x64, 0x32, 0x46,
-    0x30, 0x5a, 0x58, 0x4a, 0x36, 0x0a, 0x62, 0x32, 0x39, 0x70, 0x4c, 0x6e,
-    0x52, 0x6c, 0x63, 0x33, 0x51, 0x75, 0x5a, 0x32, 0x39, 0x76, 0x5a, 0x32,
-    0x78, 0x6c, 0x4c, 0x6d, 0x4a, 0x6c, 0x67, 0x68, 0x49, 0x71, 0x4c, 0x6e,
-    0x52, 0x6c, 0x63, 0x33, 0x51, 0x75, 0x65, 0x57, 0x39, 0x31, 0x64, 0x48,
-    0x56, 0x69, 0x5a, 0x53, 0x35, 0x6a, 0x62, 0x32, 0x32, 0x48, 0x42, 0x4d,
-    0x43, 0x6f, 0x41, 0x51, 0x4d, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x0a, 0x4b,
-    0x6f, 0x5a, 0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x46, 0x42,
-    0x51, 0x41, 0x44, 0x67, 0x59, 0x45, 0x41, 0x4d, 0x32, 0x49, 0x69, 0x30,
-    0x4c, 0x67, 0x54, 0x47, 0x62, 0x4a, 0x31, 0x6a, 0x34, 0x6f, 0x71, 0x58,
-    0x39, 0x62, 0x78, 0x56, 0x63, 0x78, 0x6d, 0x2b, 0x2f, 0x52, 0x35, 0x59,
-    0x66, 0x38, 0x6f, 0x69, 0x30, 0x61, 0x5a, 0x71, 0x54, 0x4a, 0x6c, 0x6e,
-    0x4c, 0x59, 0x53, 0x0a, 0x77, 0x58, 0x63, 0x42, 0x79, 0x6b, 0x78, 0x54,
-    0x78, 0x31, 0x38, 0x31, 0x73, 0x37, 0x57, 0x79, 0x66, 0x4a, 0x34, 0x39,
-    0x57, 0x77, 0x72, 0x59, 0x58, 0x6f, 0x37, 0x38, 0x7a, 0x54, 0x44, 0x41,
-    0x6e, 0x66, 0x31, 0x6d, 0x61, 0x30, 0x66, 0x50, 0x71, 0x33, 0x65, 0x34,
-    0x6d, 0x70, 0x73, 0x70, 0x76, 0x79, 0x6e, 0x64, 0x4c, 0x68, 0x31, 0x61,
-    0x2b, 0x4f, 0x61, 0x72, 0x48, 0x61, 0x31, 0x65, 0x0a, 0x61, 0x54, 0x30,
-    0x44, 0x49, 0x49, 0x59, 0x6b, 0x37, 0x71, 0x65, 0x45, 0x61, 0x31, 0x59,
-    0x63, 0x56, 0x6c, 0x6a, 0x78, 0x32, 0x4b, 0x79, 0x4c, 0x64, 0x30, 0x72,
-    0x31, 0x42, 0x42, 0x41, 0x66, 0x72, 0x77, 0x79, 0x47, 0x61, 0x45, 0x50,
-    0x56, 0x65, 0x4a, 0x51, 0x56, 0x59, 0x57, 0x61, 0x4f, 0x4a, 0x52, 0x55,
-    0x32, 0x77, 0x65, 0x2f, 0x4b, 0x44, 0x34, 0x6f, 0x6a, 0x66, 0x39, 0x73,
-    0x3d, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43,
+    0x5a, 0x32, 0x38, 0x78, 0x46, 0x54, 0x41, 0x54, 0x42, 0x67, 0x4e, 0x56,
+    0x42, 0x41, 0x6f, 0x54, 0x44, 0x45, 0x56, 0x34, 0x59, 0x57, 0x31, 0x77,
+    0x62, 0x47, 0x55, 0x73, 0x49, 0x45, 0x4e, 0x76, 0x4c, 0x6a, 0x45, 0x61,
+    0x4d, 0x42, 0x67, 0x47, 0x41, 0x31, 0x55, 0x45, 0x41, 0x78, 0x51, 0x52,
+    0x4b, 0x69, 0x35, 0x30, 0x0a, 0x5a, 0x58, 0x4e, 0x30, 0x4c, 0x6d, 0x64,
+    0x76, 0x62, 0x32, 0x64, 0x73, 0x5a, 0x53, 0x35, 0x6a, 0x62, 0x32, 0x30,
+    0x77, 0x67, 0x5a, 0x38, 0x77, 0x44, 0x51, 0x59, 0x4a, 0x4b, 0x6f, 0x5a,
+    0x49, 0x68, 0x76, 0x63, 0x4e, 0x41, 0x51, 0x45, 0x42, 0x42, 0x51, 0x41,
+    0x44, 0x67, 0x59, 0x30, 0x41, 0x4d, 0x49, 0x47, 0x4a, 0x41, 0x6f, 0x47,
+    0x42, 0x41, 0x4f, 0x48, 0x44, 0x46, 0x53, 0x63, 0x6f, 0x0a, 0x4c, 0x43,
+    0x56, 0x4a, 0x70, 0x59, 0x44, 0x44, 0x4d, 0x34, 0x48, 0x59, 0x74, 0x49,
+    0x64, 0x56, 0x36, 0x41, 0x6b, 0x65, 0x2f, 0x73, 0x4d, 0x4e, 0x61, 0x61,
+    0x4b, 0x64, 0x4f, 0x44, 0x6a, 0x44, 0x4d, 0x73, 0x75, 0x78, 0x2f, 0x34,
+    0x74, 0x44, 0x79, 0x64, 0x6c, 0x75, 0x6d, 0x4e, 0x2b, 0x66, 0x6d, 0x2b,
+    0x41, 0x6a, 0x50, 0x45, 0x4b, 0x35, 0x47, 0x48, 0x68, 0x47, 0x6e, 0x31,
+    0x42, 0x67, 0x0a, 0x7a, 0x6b, 0x57, 0x46, 0x2b, 0x73, 0x6c, 0x66, 0x33,
+    0x42, 0x78, 0x68, 0x72, 0x41, 0x2f, 0x38, 0x64, 0x4e, 0x73, 0x6e, 0x75,
+    0x6e, 0x73, 0x74, 0x56, 0x41, 0x37, 0x5a, 0x42, 0x67, 0x41, 0x2f, 0x35,
+    0x71, 0x51, 0x78, 0x4d, 0x66, 0x47, 0x41, 0x71, 0x34, 0x77, 0x48, 0x4e,
+    0x56, 0x58, 0x37, 0x37, 0x66, 0x42, 0x5a, 0x4f, 0x67, 0x70, 0x39, 0x56,
+    0x6c, 0x53, 0x4d, 0x56, 0x66, 0x79, 0x64, 0x0a, 0x39, 0x4e, 0x38, 0x59,
+    0x77, 0x62, 0x42, 0x59, 0x41, 0x63, 0x6b, 0x4f, 0x65, 0x55, 0x51, 0x61,
+    0x64, 0x54, 0x69, 0x32, 0x58, 0x31, 0x53, 0x36, 0x4f, 0x67, 0x4a, 0x58,
+    0x67, 0x51, 0x30, 0x6d, 0x33, 0x4d, 0x57, 0x68, 0x41, 0x67, 0x4d, 0x42,
+    0x41, 0x41, 0x47, 0x6a, 0x61, 0x7a, 0x42, 0x70, 0x4d, 0x41, 0x6b, 0x47,
+    0x41, 0x31, 0x55, 0x64, 0x45, 0x77, 0x51, 0x43, 0x4d, 0x41, 0x41, 0x77,
+    0x0a, 0x43, 0x77, 0x59, 0x44, 0x56, 0x52, 0x30, 0x50, 0x42, 0x41, 0x51,
+    0x44, 0x41, 0x67, 0x58, 0x67, 0x4d, 0x45, 0x38, 0x47, 0x41, 0x31, 0x55,
+    0x64, 0x45, 0x51, 0x52, 0x49, 0x4d, 0x45, 0x61, 0x43, 0x45, 0x43, 0x6f,
+    0x75, 0x64, 0x47, 0x56, 0x7a, 0x64, 0x43, 0x35, 0x6e, 0x62, 0x32, 0x39,
+    0x6e, 0x62, 0x47, 0x55, 0x75, 0x5a, 0x6e, 0x4b, 0x43, 0x47, 0x48, 0x64,
+    0x68, 0x64, 0x47, 0x56, 0x79, 0x0a, 0x65, 0x6d, 0x39, 0x76, 0x61, 0x53,
+    0x35, 0x30, 0x5a, 0x58, 0x4e, 0x30, 0x4c, 0x6d, 0x64, 0x76, 0x62, 0x32,
+    0x64, 0x73, 0x5a, 0x53, 0x35, 0x69, 0x5a, 0x59, 0x49, 0x53, 0x4b, 0x69,
+    0x35, 0x30, 0x5a, 0x58, 0x4e, 0x30, 0x4c, 0x6e, 0x6c, 0x76, 0x64, 0x58,
+    0x52, 0x31, 0x59, 0x6d, 0x55, 0x75, 0x59, 0x32, 0x39, 0x74, 0x68, 0x77,
+    0x54, 0x41, 0x71, 0x41, 0x45, 0x44, 0x4d, 0x41, 0x30, 0x47, 0x0a, 0x43,
+    0x53, 0x71, 0x47, 0x53, 0x49, 0x62, 0x33, 0x44, 0x51, 0x45, 0x42, 0x43,
+    0x77, 0x55, 0x41, 0x41, 0x34, 0x47, 0x42, 0x41, 0x4a, 0x46, 0x58, 0x56,
+    0x69, 0x66, 0x51, 0x4e, 0x75, 0x62, 0x31, 0x4c, 0x55, 0x50, 0x34, 0x4a,
+    0x6c, 0x6e, 0x58, 0x35, 0x6c, 0x58, 0x4e, 0x6c, 0x6f, 0x38, 0x46, 0x78,
+    0x5a, 0x32, 0x61, 0x31, 0x32, 0x41, 0x46, 0x51, 0x73, 0x2b, 0x62, 0x7a,
+    0x6f, 0x4a, 0x36, 0x0a, 0x68, 0x4d, 0x30, 0x34, 0x34, 0x45, 0x44, 0x6a,
+    0x71, 0x79, 0x78, 0x55, 0x71, 0x53, 0x62, 0x56, 0x65, 0x50, 0x4b, 0x30,
+    0x6e, 0x69, 0x33, 0x77, 0x31, 0x66, 0x48, 0x51, 0x42, 0x35, 0x72, 0x59,
+    0x39, 0x79, 0x59, 0x43, 0x35, 0x66, 0x38, 0x47, 0x37, 0x61, 0x71, 0x71,
+    0x54, 0x59, 0x31, 0x51, 0x4f, 0x68, 0x6f, 0x55, 0x6b, 0x38, 0x5a, 0x54,
+    0x53, 0x54, 0x52, 0x70, 0x6e, 0x6b, 0x54, 0x68, 0x0a, 0x79, 0x34, 0x6a,
+    0x6a, 0x64, 0x76, 0x54, 0x5a, 0x65, 0x4c, 0x44, 0x56, 0x42, 0x6c, 0x75,
+    0x65, 0x5a, 0x55, 0x54, 0x44, 0x52, 0x6d, 0x79, 0x32, 0x66, 0x65, 0x59,
+    0x35, 0x61, 0x5a, 0x49, 0x55, 0x31, 0x38, 0x76, 0x46, 0x44, 0x4b, 0x30,
+    0x38, 0x64, 0x54, 0x47, 0x30, 0x41, 0x38, 0x37, 0x70, 0x70, 0x70, 0x75,
+    0x76, 0x31, 0x4c, 0x4e, 0x49, 0x52, 0x33, 0x6c, 0x6f, 0x76, 0x65, 0x55,
+    0x38, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x45, 0x4e, 0x44, 0x20, 0x43,
     0x45, 0x52, 0x54, 0x49, 0x46, 0x49, 0x43, 0x41, 0x54, 0x45, 0x2d, 0x2d,
     0x2d, 0x2d, 0x2d, 0x0a, 0x00};
diff --git a/test/core/end2end/fixtures/h2_fakesec.c b/test/core/end2end/fixtures/h2_fakesec.c
index 3e64cc08e88becae2078069c30f5d0bccd0f980f..bc009e1df1ef26e45478dc7fb0137a761227d9f4 100644
--- a/test/core/end2end/fixtures/h2_fakesec.c
+++ b/test/core/end2end/fixtures/h2_fakesec.c
@@ -73,14 +73,14 @@ static void process_auth_failure(void *state, grpc_auth_context *ctx,
   cb(user_data, NULL, 0, NULL, 0, GRPC_STATUS_UNAUTHENTICATED, NULL);
 }
 
-static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f,
-                                                grpc_channel_args *client_args,
-                                                grpc_credentials *creds) {
+static void chttp2_init_client_secure_fullstack(
+    grpc_end2end_test_fixture *f, grpc_channel_args *client_args,
+    grpc_channel_credentials *creds) {
   fullstack_secure_fixture_data *ffd = f->fixture_data;
   f->client =
       grpc_secure_channel_create(creds, ffd->localaddr, client_args, NULL);
   GPR_ASSERT(f->client != NULL);
-  grpc_credentials_release(creds);
+  grpc_channel_credentials_release(creds);
 }
 
 static void chttp2_init_server_secure_fullstack(
@@ -106,7 +106,7 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
 
 static void chttp2_init_client_fake_secure_fullstack(
     grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
-  grpc_credentials *fake_ts_creds =
+  grpc_channel_credentials *fake_ts_creds =
       grpc_fake_transport_security_credentials_create();
   chttp2_init_client_secure_fullstack(f, client_args, fake_ts_creds);
 }
diff --git a/test/core/end2end/fixtures/h2_oauth2.c b/test/core/end2end/fixtures/h2_oauth2.c
index 10db6c2c6a5b4b38dbed9a7daf47a59c1d7f0e1c..7a34cc67d875a0b0f69da00cdd7b84afb7c1a117 100644
--- a/test/core/end2end/fixtures/h2_oauth2.c
+++ b/test/core/end2end/fixtures/h2_oauth2.c
@@ -118,14 +118,14 @@ static grpc_end2end_test_fixture chttp2_create_fixture_secure_fullstack(
   return f;
 }
 
-static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f,
-                                                grpc_channel_args *client_args,
-                                                grpc_credentials *creds) {
+static void chttp2_init_client_secure_fullstack(
+    grpc_end2end_test_fixture *f, grpc_channel_args *client_args,
+    grpc_channel_credentials *creds) {
   fullstack_secure_fixture_data *ffd = f->fixture_data;
   f->client =
       grpc_secure_channel_create(creds, ffd->localaddr, client_args, NULL);
   GPR_ASSERT(f->client != NULL);
-  grpc_credentials_release(creds);
+  grpc_channel_credentials_release(creds);
 }
 
 static void chttp2_init_server_secure_fullstack(
@@ -151,12 +151,12 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
 
 static void chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack(
     grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
-  grpc_credentials *ssl_creds =
+  grpc_channel_credentials *ssl_creds =
       grpc_ssl_credentials_create(test_root_cert, NULL, NULL);
-  grpc_credentials *oauth2_creds =
+  grpc_call_credentials *oauth2_creds =
       grpc_md_only_test_credentials_create("Authorization", oauth2_md, 1);
-  grpc_credentials *ssl_oauth2_creds =
-      grpc_composite_credentials_create(ssl_creds, oauth2_creds, NULL);
+  grpc_channel_credentials *ssl_oauth2_creds =
+      grpc_composite_channel_credentials_create(ssl_creds, oauth2_creds, NULL);
   grpc_arg ssl_name_override = {GRPC_ARG_STRING,
                                 GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
                                 {"foo.test.google.fr"}};
@@ -164,8 +164,8 @@ static void chttp2_init_client_simple_ssl_with_oauth2_secure_fullstack(
       grpc_channel_args_copy_and_add(client_args, &ssl_name_override, 1);
   chttp2_init_client_secure_fullstack(f, new_client_args, ssl_oauth2_creds);
   grpc_channel_args_destroy(new_client_args);
-  grpc_credentials_release(ssl_creds);
-  grpc_credentials_release(oauth2_creds);
+  grpc_channel_credentials_release(ssl_creds);
+  grpc_call_credentials_release(oauth2_creds);
 }
 
 static int fail_server_auth_check(grpc_channel_args *server_args) {
diff --git a/test/core/end2end/fixtures/h2_ssl+poll.c b/test/core/end2end/fixtures/h2_ssl+poll.c
index c2f41f48869179bba272efc2bde547e8f7a33630..37e1758f00bcea71c53fe6a6abd2912bca99d291 100644
--- a/test/core/end2end/fixtures/h2_ssl+poll.c
+++ b/test/core/end2end/fixtures/h2_ssl+poll.c
@@ -76,14 +76,14 @@ static void process_auth_failure(void *state, grpc_auth_context *ctx,
   cb(user_data, NULL, 0, NULL, 0, GRPC_STATUS_UNAUTHENTICATED, NULL);
 }
 
-static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f,
-                                                grpc_channel_args *client_args,
-                                                grpc_credentials *creds) {
+static void chttp2_init_client_secure_fullstack(
+    grpc_end2end_test_fixture *f, grpc_channel_args *client_args,
+    grpc_channel_credentials *creds) {
   fullstack_secure_fixture_data *ffd = f->fixture_data;
   f->client =
       grpc_secure_channel_create(creds, ffd->localaddr, client_args, NULL);
   GPR_ASSERT(f->client != NULL);
-  grpc_credentials_release(creds);
+  grpc_channel_credentials_release(creds);
 }
 
 static void chttp2_init_server_secure_fullstack(
@@ -109,7 +109,8 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
 
 static void chttp2_init_client_simple_ssl_secure_fullstack(
     grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
-  grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL);
+  grpc_channel_credentials *ssl_creds =
+      grpc_ssl_credentials_create(NULL, NULL, NULL);
   grpc_arg ssl_name_override = {GRPC_ARG_STRING,
                                 GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
                                 {"foo.test.google.fr"}};
diff --git a/test/core/end2end/fixtures/h2_ssl.c b/test/core/end2end/fixtures/h2_ssl.c
index 896c60c5077d50883751be9993fd7ed2b287c354..f5a006bd08606e54863e8d60c71357924ec7f4f5 100644
--- a/test/core/end2end/fixtures/h2_ssl.c
+++ b/test/core/end2end/fixtures/h2_ssl.c
@@ -76,14 +76,14 @@ static void process_auth_failure(void *state, grpc_auth_context *ctx,
   cb(user_data, NULL, 0, NULL, 0, GRPC_STATUS_UNAUTHENTICATED, NULL);
 }
 
-static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f,
-                                                grpc_channel_args *client_args,
-                                                grpc_credentials *creds) {
+static void chttp2_init_client_secure_fullstack(
+    grpc_end2end_test_fixture *f, grpc_channel_args *client_args,
+    grpc_channel_credentials *creds) {
   fullstack_secure_fixture_data *ffd = f->fixture_data;
   f->client =
       grpc_secure_channel_create(creds, ffd->localaddr, client_args, NULL);
   GPR_ASSERT(f->client != NULL);
-  grpc_credentials_release(creds);
+  grpc_channel_credentials_release(creds);
 }
 
 static void chttp2_init_server_secure_fullstack(
@@ -109,7 +109,8 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
 
 static void chttp2_init_client_simple_ssl_secure_fullstack(
     grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
-  grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL);
+  grpc_channel_credentials *ssl_creds =
+      grpc_ssl_credentials_create(NULL, NULL, NULL);
   grpc_arg ssl_name_override = {GRPC_ARG_STRING,
                                 GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
                                 {"foo.test.google.fr"}};
diff --git a/test/core/end2end/fixtures/h2_ssl_proxy.c b/test/core/end2end/fixtures/h2_ssl_proxy.c
index 413a8b84cd03144293c9cf1fa3a2d5ab5c69fd34..7233cdbe2d882e5439043eca83b2ce407231d7c7 100644
--- a/test/core/end2end/fixtures/h2_ssl_proxy.c
+++ b/test/core/end2end/fixtures/h2_ssl_proxy.c
@@ -66,7 +66,8 @@ static grpc_server *create_proxy_server(const char *port) {
 
 static grpc_channel *create_proxy_client(const char *target) {
   grpc_channel *channel;
-  grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL);
+  grpc_channel_credentials *ssl_creds =
+      grpc_ssl_credentials_create(NULL, NULL, NULL);
   grpc_arg ssl_name_override = {GRPC_ARG_STRING,
                                 GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
                                 {"foo.test.google.fr"}};
@@ -74,7 +75,7 @@ static grpc_channel *create_proxy_client(const char *target) {
   client_args.num_args = 1;
   client_args.args = &ssl_name_override;
   channel = grpc_secure_channel_create(ssl_creds, target, &client_args, NULL);
-  grpc_credentials_release(ssl_creds);
+  grpc_channel_credentials_release(ssl_creds);
   return channel;
 }
 
@@ -104,15 +105,15 @@ static void process_auth_failure(void *state, grpc_auth_context *ctx,
   cb(user_data, NULL, 0, NULL, 0, GRPC_STATUS_UNAUTHENTICATED, NULL);
 }
 
-static void chttp2_init_client_secure_fullstack(grpc_end2end_test_fixture *f,
-                                                grpc_channel_args *client_args,
-                                                grpc_credentials *creds) {
+static void chttp2_init_client_secure_fullstack(
+    grpc_end2end_test_fixture *f, grpc_channel_args *client_args,
+    grpc_channel_credentials *creds) {
   fullstack_secure_fixture_data *ffd = f->fixture_data;
   f->client = grpc_secure_channel_create(
       creds, grpc_end2end_proxy_get_client_target(ffd->proxy), client_args,
       NULL);
   GPR_ASSERT(f->client != NULL);
-  grpc_credentials_release(creds);
+  grpc_channel_credentials_release(creds);
 }
 
 static void chttp2_init_server_secure_fullstack(
@@ -138,7 +139,8 @@ void chttp2_tear_down_secure_fullstack(grpc_end2end_test_fixture *f) {
 
 static void chttp2_init_client_simple_ssl_secure_fullstack(
     grpc_end2end_test_fixture *f, grpc_channel_args *client_args) {
-  grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL);
+  grpc_channel_credentials *ssl_creds =
+      grpc_ssl_credentials_create(NULL, NULL, NULL);
   grpc_arg ssl_name_override = {GRPC_ARG_STRING,
                                 GRPC_SSL_TARGET_NAME_OVERRIDE_ARG,
                                 {"foo.test.google.fr"}};
diff --git a/test/core/end2end/tests/call_creds.c b/test/core/end2end/tests/call_creds.c
index 4aeade1336e1f6fac7a90439f0bfaa6192cd86a8..bbfad21b62e101df5348ce4cd92a4ba3536d8145 100644
--- a/test/core/end2end/tests/call_creds.c
+++ b/test/core/end2end/tests/call_creds.c
@@ -132,27 +132,6 @@ static void print_auth_context(int is_client, const grpc_auth_context *ctx) {
   }
 }
 
-static void test_call_creds_failure(grpc_end2end_test_config config) {
-  grpc_call *c;
-  grpc_credentials *creds = NULL;
-  grpc_end2end_test_fixture f =
-      begin_test(config, "test_call_creds_failure", 0);
-  gpr_timespec deadline = five_seconds_time();
-  c = grpc_channel_create_call(f.client, NULL, GRPC_PROPAGATE_DEFAULTS, f.cq,
-                               "/foo", "foo.test.google.fr", deadline, NULL);
-  GPR_ASSERT(c);
-
-  /* Try with credentials unfit to be set on a call (channel creds). */
-  creds = grpc_fake_transport_security_credentials_create();
-  GPR_ASSERT(grpc_call_set_credentials(c, creds) != GRPC_CALL_OK);
-  grpc_credentials_release(creds);
-
-  grpc_call_destroy(c);
-
-  end_test(&f);
-  config.tear_down_data(&f);
-}
-
 static void request_response_with_payload_and_call_creds(
     const char *test_name, grpc_end2end_test_config config,
     override_mode mode) {
@@ -180,7 +159,7 @@ static void request_response_with_payload_and_call_creds(
   char *details = NULL;
   size_t details_capacity = 0;
   int was_cancelled = 2;
-  grpc_credentials *creds = NULL;
+  grpc_call_credentials *creds = NULL;
   grpc_auth_context *s_auth_context = NULL;
   grpc_auth_context *c_auth_context = NULL;
 
@@ -197,7 +176,7 @@ static void request_response_with_payload_and_call_creds(
     case NONE:
       break;
     case OVERRIDE:
-      grpc_credentials_release(creds);
+      grpc_call_credentials_release(creds);
       creds = grpc_google_iam_credentials_create(overridden_iam_token,
                                                  overridden_iam_selector, NULL);
       GPR_ASSERT(creds != NULL);
@@ -207,7 +186,7 @@ static void request_response_with_payload_and_call_creds(
       GPR_ASSERT(grpc_call_set_credentials(c, NULL) == GRPC_CALL_OK);
       break;
   }
-  grpc_credentials_release(creds);
+  grpc_call_credentials_release(creds);
 
   grpc_metadata_array_init(&initial_metadata_recv);
   grpc_metadata_array_init(&trailing_metadata_recv);
@@ -412,7 +391,7 @@ static void test_request_with_server_rejecting_client_creds(
   gpr_slice request_payload_slice = gpr_slice_from_copied_string("hello world");
   grpc_byte_buffer *request_payload =
       grpc_raw_byte_buffer_create(&request_payload_slice, 1);
-  grpc_credentials *creds;
+  grpc_call_credentials *creds;
 
   f = begin_test(config, "test_request_with_server_rejecting_client_creds", 1);
   cqv = cq_verifier_create(f.cq);
@@ -424,7 +403,7 @@ static void test_request_with_server_rejecting_client_creds(
   creds = grpc_google_iam_credentials_create(iam_token, iam_selector, NULL);
   GPR_ASSERT(creds != NULL);
   GPR_ASSERT(grpc_call_set_credentials(c, creds) == GRPC_CALL_OK);
-  grpc_credentials_release(creds);
+  grpc_call_credentials_release(creds);
 
   grpc_metadata_array_init(&initial_metadata_recv);
   grpc_metadata_array_init(&trailing_metadata_recv);
@@ -490,7 +469,6 @@ static void test_request_with_server_rejecting_client_creds(
 
 void grpc_end2end_tests(grpc_end2end_test_config config) {
   if (config.feature_mask & FEATURE_MASK_SUPPORTS_PER_CALL_CREDENTIALS) {
-    test_call_creds_failure(config);
     test_request_response_with_payload_and_call_creds(config);
     test_request_response_with_payload_and_overridden_call_creds(config);
     test_request_response_with_payload_and_deleted_call_creds(config);
diff --git a/test/core/security/credentials_test.c b/test/core/security/credentials_test.c
index 5c1e0f4b948750069be9c1df0539e776dd061eb1..dcb35e5309683f2f50b312ce0fb654164cc212f7 100644
--- a/test/core/security/credentials_test.c
+++ b/test/core/security/credentials_test.c
@@ -50,11 +50,24 @@
 
 #include <openssl/rsa.h>
 
+/* -- Mock channel credentials. -- */
+
+static grpc_channel_credentials *grpc_mock_channel_credentials_create(
+    const grpc_channel_credentials_vtable *vtable) {
+  grpc_channel_credentials *c = gpr_malloc(sizeof(*c));
+  memset(c, 0, sizeof(*c));
+  c->type = "mock";
+  c->vtable = vtable;
+  gpr_ref_init(&c->refcount, 1);
+  return c;
+}
+
+/* -- Constants. -- */
+
 static const char test_google_iam_authorization_token[] = "blahblahblhahb";
 static const char test_google_iam_authority_selector[] = "respectmyauthoritah";
 static const char test_oauth2_bearer_token[] =
     "Bearer blaaslkdjfaslkdfasdsfasf";
-static const char test_root_cert[] = "I am the root!";
 
 /* This JSON key was generated with the GCE console and revoked immediately.
    The identifiers have been changed as well.
@@ -113,6 +126,8 @@ static const char test_signed_jwt[] =
 static const char test_service_url[] = "https://foo.com/foo.v1";
 static const char other_test_service_url[] = "https://bar.com/bar.v1";
 
+/* -- Utils. -- */
+
 static char *test_json_key_str(void) {
   size_t result_len = strlen(test_json_key_str_part1) +
                       strlen(test_json_key_str_part2) +
@@ -141,6 +156,8 @@ static grpc_httpcli_response http_response(int status, const char *body) {
   return response;
 }
 
+/* -- Tests. -- */
+
 static void test_empty_md_store(void) {
   grpc_credentials_md_store *store = grpc_credentials_md_store_create(0);
   GPR_ASSERT(store->num_entries == 0);
@@ -219,7 +236,7 @@ static void test_oauth2_token_fetcher_creds_parsing_ok(void) {
   GPR_ASSERT(token_lifetime.tv_sec == 3599);
   GPR_ASSERT(token_lifetime.tv_nsec == 0);
   GPR_ASSERT(token_md->num_entries == 1);
-  GPR_ASSERT(gpr_slice_str_cmp(token_md->entries[0].key, "Authorization") == 0);
+  GPR_ASSERT(gpr_slice_str_cmp(token_md->entries[0].key, "authorization") == 0);
   GPR_ASSERT(gpr_slice_str_cmp(token_md->entries[0].value,
                                "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_") ==
              0);
@@ -319,7 +336,7 @@ static void check_google_iam_metadata(grpc_exec_ctx *exec_ctx, void *user_data,
                                       grpc_credentials_md *md_elems,
                                       size_t num_md,
                                       grpc_credentials_status status) {
-  grpc_credentials *c = (grpc_credentials *)user_data;
+  grpc_call_credentials *c = (grpc_call_credentials *)user_data;
   expected_md emd[] = {{GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY,
                         test_google_iam_authorization_token},
                        {GRPC_IAM_AUTHORITY_SELECTOR_METADATA_KEY,
@@ -327,17 +344,15 @@ static void check_google_iam_metadata(grpc_exec_ctx *exec_ctx, void *user_data,
   GPR_ASSERT(status == GRPC_CREDENTIALS_OK);
   GPR_ASSERT(num_md == 2);
   check_metadata(emd, md_elems, num_md);
-  grpc_credentials_unref(c);
+  grpc_call_credentials_unref(c);
 }
 
 static void test_google_iam_creds(void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_credentials *creds = grpc_google_iam_credentials_create(
+  grpc_call_credentials *creds = grpc_google_iam_credentials_create(
       test_google_iam_authorization_token, test_google_iam_authority_selector,
       NULL);
-  GPR_ASSERT(grpc_credentials_has_request_metadata(creds));
-  GPR_ASSERT(grpc_credentials_has_request_metadata_only(creds));
-  grpc_credentials_get_request_metadata(&exec_ctx, creds, NULL,
+  grpc_call_credentials_get_request_metadata(&exec_ctx, creds, NULL,
                                         test_service_url,
                                         check_google_iam_metadata, creds);
   grpc_exec_ctx_finish(&exec_ctx);
@@ -348,81 +363,58 @@ static void check_access_token_metadata(grpc_exec_ctx *exec_ctx,
                                         grpc_credentials_md *md_elems,
                                         size_t num_md,
                                         grpc_credentials_status status) {
-  grpc_credentials *c = (grpc_credentials *)user_data;
+  grpc_call_credentials *c = (grpc_call_credentials *)user_data;
   expected_md emd[] = {{GRPC_AUTHORIZATION_METADATA_KEY, "Bearer blah"}};
   GPR_ASSERT(status == GRPC_CREDENTIALS_OK);
   GPR_ASSERT(num_md == 1);
   check_metadata(emd, md_elems, num_md);
-  grpc_credentials_unref(c);
+  grpc_call_credentials_unref(c);
 }
 
 static void test_access_token_creds(void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_credentials *creds = grpc_access_token_credentials_create("blah", NULL);
-  GPR_ASSERT(grpc_credentials_has_request_metadata(creds));
-  GPR_ASSERT(grpc_credentials_has_request_metadata_only(creds));
-  GPR_ASSERT(strcmp(creds->type, GRPC_CREDENTIALS_TYPE_OAUTH2) == 0);
-  grpc_credentials_get_request_metadata(&exec_ctx, creds, NULL,
-                                        test_service_url,
-                                        check_access_token_metadata, creds);
+  grpc_call_credentials *creds =
+      grpc_access_token_credentials_create("blah", NULL);
+  GPR_ASSERT(strcmp(creds->type, GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0);
+  grpc_call_credentials_get_request_metadata(
+      &exec_ctx, creds, NULL, test_service_url, check_access_token_metadata,
+      creds);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
-static void check_ssl_oauth2_composite_metadata(
+static grpc_security_status check_channel_oauth2_create_security_connector(
+    grpc_channel_credentials *c, grpc_call_credentials *call_creds,
+    const char *target, const grpc_channel_args *args,
+    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+  GPR_ASSERT(strcmp(c->type, "mock") == 0);
+  GPR_ASSERT(call_creds != NULL);
+  GPR_ASSERT(strcmp(call_creds->type, GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0);
+  return GRPC_SECURITY_OK;
+}
+
+static void test_channel_oauth2_composite_creds(void) {
+  grpc_channel_args *new_args;
+  grpc_channel_credentials_vtable vtable = {
+      NULL, check_channel_oauth2_create_security_connector};
+  grpc_channel_credentials *channel_creds =
+      grpc_mock_channel_credentials_create(&vtable);
+  grpc_call_credentials *oauth2_creds =
+      grpc_access_token_credentials_create("blah", NULL);
+  grpc_channel_credentials *channel_oauth2_creds =
+      grpc_composite_channel_credentials_create(channel_creds, oauth2_creds,
+                                                NULL);
+  grpc_channel_credentials_release(channel_creds);
+  grpc_call_credentials_release(oauth2_creds);
+  GPR_ASSERT(grpc_channel_credentials_create_security_connector(
+                 channel_oauth2_creds, NULL, NULL, NULL, &new_args) ==
+             GRPC_SECURITY_OK);
+  grpc_channel_credentials_release(channel_oauth2_creds);
+}
+
+static void check_oauth2_google_iam_composite_metadata(
     grpc_exec_ctx *exec_ctx, void *user_data, grpc_credentials_md *md_elems,
     size_t num_md, grpc_credentials_status status) {
-  grpc_credentials *c = (grpc_credentials *)user_data;
-  expected_md emd[] = {
-      {GRPC_AUTHORIZATION_METADATA_KEY, test_oauth2_bearer_token}};
-  GPR_ASSERT(status == GRPC_CREDENTIALS_OK);
-  GPR_ASSERT(num_md == 1);
-  check_metadata(emd, md_elems, num_md);
-  grpc_credentials_unref(c);
-}
-
-static void test_ssl_oauth2_composite_creds(void) {
-  grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_credentials *ssl_creds =
-      grpc_ssl_credentials_create(test_root_cert, NULL, NULL);
-  const grpc_credentials_array *creds_array;
-  grpc_credentials *oauth2_creds = grpc_md_only_test_credentials_create(
-      "Authorization", test_oauth2_bearer_token, 0);
-  grpc_credentials *composite_creds =
-      grpc_composite_credentials_create(ssl_creds, oauth2_creds, NULL);
-  grpc_credentials_unref(ssl_creds);
-  grpc_credentials_unref(oauth2_creds);
-  GPR_ASSERT(strcmp(composite_creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) ==
-             0);
-  GPR_ASSERT(grpc_credentials_has_request_metadata(composite_creds));
-  GPR_ASSERT(!grpc_credentials_has_request_metadata_only(composite_creds));
-  creds_array = grpc_composite_credentials_get_credentials(composite_creds);
-  GPR_ASSERT(creds_array->num_creds == 2);
-  GPR_ASSERT(strcmp(creds_array->creds_array[0]->type,
-                    GRPC_CREDENTIALS_TYPE_SSL) == 0);
-  GPR_ASSERT(strcmp(creds_array->creds_array[1]->type,
-                    GRPC_CREDENTIALS_TYPE_OAUTH2) == 0);
-  grpc_credentials_get_request_metadata(
-      &exec_ctx, composite_creds, NULL, test_service_url,
-      check_ssl_oauth2_composite_metadata, composite_creds);
-  grpc_exec_ctx_finish(&exec_ctx);
-}
-
-void test_ssl_fake_transport_security_composite_creds_failure(void) {
-  grpc_credentials *ssl_creds = grpc_ssl_credentials_create(NULL, NULL, NULL);
-  grpc_credentials *fake_transport_security_creds =
-      grpc_fake_transport_security_credentials_create();
-
-  /* 2 connector credentials: should not work. */
-  GPR_ASSERT(grpc_composite_credentials_create(
-                 ssl_creds, fake_transport_security_creds, NULL) == NULL);
-  grpc_credentials_unref(ssl_creds);
-  grpc_credentials_unref(fake_transport_security_creds);
-}
-
-static void check_ssl_oauth2_google_iam_composite_metadata(
-    grpc_exec_ctx *exec_ctx, void *user_data, grpc_credentials_md *md_elems,
-    size_t num_md, grpc_credentials_status status) {
-  grpc_credentials *c = (grpc_credentials *)user_data;
+  grpc_call_credentials *c = (grpc_call_credentials *)user_data;
   expected_md emd[] = {
       {GRPC_AUTHORIZATION_METADATA_KEY, test_oauth2_bearer_token},
       {GRPC_IAM_AUTHORIZATION_TOKEN_METADATA_KEY,
@@ -432,51 +424,88 @@ static void check_ssl_oauth2_google_iam_composite_metadata(
   GPR_ASSERT(status == GRPC_CREDENTIALS_OK);
   GPR_ASSERT(num_md == 3);
   check_metadata(emd, md_elems, num_md);
-  grpc_credentials_unref(c);
+  grpc_call_credentials_unref(c);
 }
 
-static void test_ssl_oauth2_google_iam_composite_creds(void) {
+static void test_oauth2_google_iam_composite_creds(void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_credentials *ssl_creds =
-      grpc_ssl_credentials_create(test_root_cert, NULL, NULL);
-  const grpc_credentials_array *creds_array;
-  grpc_credentials *oauth2_creds = grpc_md_only_test_credentials_create(
-      "Authorization", test_oauth2_bearer_token, 0);
-  grpc_credentials *aux_creds =
-      grpc_composite_credentials_create(ssl_creds, oauth2_creds, NULL);
-  grpc_credentials *google_iam_creds = grpc_google_iam_credentials_create(
+  const grpc_call_credentials_array *creds_array;
+  grpc_call_credentials *oauth2_creds = grpc_md_only_test_credentials_create(
+      "authorization", test_oauth2_bearer_token, 0);
+  grpc_call_credentials *google_iam_creds = grpc_google_iam_credentials_create(
       test_google_iam_authorization_token, test_google_iam_authority_selector,
       NULL);
-  grpc_credentials *composite_creds =
-      grpc_composite_credentials_create(aux_creds, google_iam_creds, NULL);
-  grpc_credentials_unref(ssl_creds);
-  grpc_credentials_unref(oauth2_creds);
-  grpc_credentials_unref(aux_creds);
-  grpc_credentials_unref(google_iam_creds);
-  GPR_ASSERT(strcmp(composite_creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) ==
-             0);
-  GPR_ASSERT(grpc_credentials_has_request_metadata(composite_creds));
-  GPR_ASSERT(!grpc_credentials_has_request_metadata_only(composite_creds));
-  creds_array = grpc_composite_credentials_get_credentials(composite_creds);
-  GPR_ASSERT(creds_array->num_creds == 3);
+  grpc_call_credentials *composite_creds =
+      grpc_composite_call_credentials_create(oauth2_creds, google_iam_creds, NULL);
+  grpc_call_credentials_unref(oauth2_creds);
+  grpc_call_credentials_unref(google_iam_creds);
+  GPR_ASSERT(
+      strcmp(composite_creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) == 0);
+  creds_array =
+      grpc_composite_call_credentials_get_credentials(composite_creds);
+  GPR_ASSERT(creds_array->num_creds == 2);
   GPR_ASSERT(strcmp(creds_array->creds_array[0]->type,
-                    GRPC_CREDENTIALS_TYPE_SSL) == 0);
+                    GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0);
   GPR_ASSERT(strcmp(creds_array->creds_array[1]->type,
-                    GRPC_CREDENTIALS_TYPE_OAUTH2) == 0);
-  GPR_ASSERT(strcmp(creds_array->creds_array[2]->type,
-                    GRPC_CREDENTIALS_TYPE_IAM) == 0);
-  grpc_credentials_get_request_metadata(
+                    GRPC_CALL_CREDENTIALS_TYPE_IAM) == 0);
+  grpc_call_credentials_get_request_metadata(
       &exec_ctx, composite_creds, NULL, test_service_url,
-      check_ssl_oauth2_google_iam_composite_metadata, composite_creds);
+      check_oauth2_google_iam_composite_metadata, composite_creds);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
+static grpc_security_status
+check_channel_oauth2_google_iam_create_security_connector(
+    grpc_channel_credentials *c, grpc_call_credentials *call_creds,
+    const char *target, const grpc_channel_args *args,
+    grpc_channel_security_connector **sc, grpc_channel_args **new_args) {
+  const grpc_call_credentials_array *creds_array;
+  GPR_ASSERT(strcmp(c->type, "mock") == 0);
+  GPR_ASSERT(call_creds != NULL);
+  GPR_ASSERT(strcmp(call_creds->type, GRPC_CALL_CREDENTIALS_TYPE_COMPOSITE) ==
+             0);
+  creds_array = grpc_composite_call_credentials_get_credentials(call_creds);
+  GPR_ASSERT(strcmp(creds_array->creds_array[0]->type,
+                    GRPC_CALL_CREDENTIALS_TYPE_OAUTH2) == 0);
+  GPR_ASSERT(strcmp(creds_array->creds_array[1]->type,
+                    GRPC_CALL_CREDENTIALS_TYPE_IAM) == 0);
+  return GRPC_SECURITY_OK;
+}
+
+static void test_channel_oauth2_google_iam_composite_creds(void) {
+  grpc_channel_args *new_args;
+  grpc_channel_credentials_vtable vtable = {
+      NULL, check_channel_oauth2_google_iam_create_security_connector};
+  grpc_channel_credentials *channel_creds =
+      grpc_mock_channel_credentials_create(&vtable);
+  grpc_call_credentials *oauth2_creds =
+      grpc_access_token_credentials_create("blah", NULL);
+  grpc_channel_credentials *channel_oauth2_creds =
+      grpc_composite_channel_credentials_create(channel_creds, oauth2_creds, NULL);
+  grpc_call_credentials *google_iam_creds = grpc_google_iam_credentials_create(
+      test_google_iam_authorization_token, test_google_iam_authority_selector,
+      NULL);
+  grpc_channel_credentials *channel_oauth2_iam_creds =
+      grpc_composite_channel_credentials_create(channel_oauth2_creds,
+                                                google_iam_creds, NULL);
+  grpc_channel_credentials_release(channel_creds);
+  grpc_call_credentials_release(oauth2_creds);
+  grpc_channel_credentials_release(channel_oauth2_creds);
+  grpc_call_credentials_release(google_iam_creds);
+
+  GPR_ASSERT(grpc_channel_credentials_create_security_connector(
+                 channel_oauth2_iam_creds, NULL, NULL, NULL, &new_args) ==
+             GRPC_SECURITY_OK);
+
+  grpc_channel_credentials_release(channel_oauth2_iam_creds);
+}
+
 static void on_oauth2_creds_get_metadata_success(
     grpc_exec_ctx *exec_ctx, void *user_data, grpc_credentials_md *md_elems,
     size_t num_md, grpc_credentials_status status) {
   GPR_ASSERT(status == GRPC_CREDENTIALS_OK);
   GPR_ASSERT(num_md == 1);
-  GPR_ASSERT(gpr_slice_str_cmp(md_elems[0].key, "Authorization") == 0);
+  GPR_ASSERT(gpr_slice_str_cmp(md_elems[0].key, "authorization") == 0);
   GPR_ASSERT(gpr_slice_str_cmp(md_elems[0].value,
                                "Bearer ya29.AHES6ZRN3-HlhAPya30GnW_bHSb_") ==
              0);
@@ -545,15 +574,13 @@ static int httpcli_get_should_not_be_called(
 
 static void test_compute_engine_creds_success(void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_credentials *compute_engine_creds =
+  grpc_call_credentials *compute_engine_creds =
       grpc_google_compute_engine_credentials_create(NULL);
-  GPR_ASSERT(grpc_credentials_has_request_metadata(compute_engine_creds));
-  GPR_ASSERT(grpc_credentials_has_request_metadata_only(compute_engine_creds));
 
   /* First request: http get should be called. */
   grpc_httpcli_set_override(compute_engine_httpcli_get_success_override,
                             httpcli_post_should_not_be_called);
-  grpc_credentials_get_request_metadata(
+  grpc_call_credentials_get_request_metadata(
       &exec_ctx, compute_engine_creds, NULL, test_service_url,
       on_oauth2_creds_get_metadata_success, (void *)test_user_data);
   grpc_exec_ctx_flush(&exec_ctx);
@@ -561,27 +588,25 @@ static void test_compute_engine_creds_success(void) {
   /* Second request: the cached token should be served directly. */
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             httpcli_post_should_not_be_called);
-  grpc_credentials_get_request_metadata(
+  grpc_call_credentials_get_request_metadata(
       &exec_ctx, compute_engine_creds, NULL, test_service_url,
       on_oauth2_creds_get_metadata_success, (void *)test_user_data);
   grpc_exec_ctx_finish(&exec_ctx);
 
-  grpc_credentials_unref(compute_engine_creds);
+  grpc_call_credentials_unref(compute_engine_creds);
   grpc_httpcli_set_override(NULL, NULL);
 }
 
 static void test_compute_engine_creds_failure(void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_credentials *compute_engine_creds =
+  grpc_call_credentials *compute_engine_creds =
       grpc_google_compute_engine_credentials_create(NULL);
   grpc_httpcli_set_override(compute_engine_httpcli_get_failure_override,
                             httpcli_post_should_not_be_called);
-  GPR_ASSERT(grpc_credentials_has_request_metadata(compute_engine_creds));
-  GPR_ASSERT(grpc_credentials_has_request_metadata_only(compute_engine_creds));
-  grpc_credentials_get_request_metadata(
+  grpc_call_credentials_get_request_metadata(
       &exec_ctx, compute_engine_creds, NULL, test_service_url,
       on_oauth2_creds_get_metadata_failure, (void *)test_user_data);
-  grpc_credentials_unref(compute_engine_creds);
+  grpc_call_credentials_unref(compute_engine_creds);
   grpc_httpcli_set_override(NULL, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -631,16 +656,14 @@ static int refresh_token_httpcli_post_failure(
 
 static void test_refresh_token_creds_success(void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_credentials *refresh_token_creds =
+  grpc_call_credentials *refresh_token_creds =
       grpc_google_refresh_token_credentials_create(test_refresh_token_str,
                                                    NULL);
-  GPR_ASSERT(grpc_credentials_has_request_metadata(refresh_token_creds));
-  GPR_ASSERT(grpc_credentials_has_request_metadata_only(refresh_token_creds));
 
   /* First request: http get should be called. */
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             refresh_token_httpcli_post_success);
-  grpc_credentials_get_request_metadata(
+  grpc_call_credentials_get_request_metadata(
       &exec_ctx, refresh_token_creds, NULL, test_service_url,
       on_oauth2_creds_get_metadata_success, (void *)test_user_data);
   grpc_exec_ctx_flush(&exec_ctx);
@@ -648,29 +671,27 @@ static void test_refresh_token_creds_success(void) {
   /* Second request: the cached token should be served directly. */
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             httpcli_post_should_not_be_called);
-  grpc_credentials_get_request_metadata(
+  grpc_call_credentials_get_request_metadata(
       &exec_ctx, refresh_token_creds, NULL, test_service_url,
       on_oauth2_creds_get_metadata_success, (void *)test_user_data);
   grpc_exec_ctx_flush(&exec_ctx);
 
-  grpc_credentials_unref(refresh_token_creds);
+  grpc_call_credentials_unref(refresh_token_creds);
   grpc_httpcli_set_override(NULL, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_refresh_token_creds_failure(void) {
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_credentials *refresh_token_creds =
+  grpc_call_credentials *refresh_token_creds =
       grpc_google_refresh_token_credentials_create(test_refresh_token_str,
                                                    NULL);
   grpc_httpcli_set_override(httpcli_get_should_not_be_called,
                             refresh_token_httpcli_post_failure);
-  GPR_ASSERT(grpc_credentials_has_request_metadata(refresh_token_creds));
-  GPR_ASSERT(grpc_credentials_has_request_metadata_only(refresh_token_creds));
-  grpc_credentials_get_request_metadata(
+  grpc_call_credentials_get_request_metadata(
       &exec_ctx, refresh_token_creds, NULL, test_service_url,
       on_oauth2_creds_get_metadata_failure, (void *)test_user_data);
-  grpc_credentials_unref(refresh_token_creds);
+  grpc_call_credentials_unref(refresh_token_creds);
   grpc_httpcli_set_override(NULL, NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -730,7 +751,7 @@ static void on_jwt_creds_get_metadata_success(grpc_exec_ctx *exec_ctx,
   gpr_asprintf(&expected_md_value, "Bearer %s", test_signed_jwt);
   GPR_ASSERT(status == GRPC_CREDENTIALS_OK);
   GPR_ASSERT(num_md == 1);
-  GPR_ASSERT(gpr_slice_str_cmp(md_elems[0].key, "Authorization") == 0);
+  GPR_ASSERT(gpr_slice_str_cmp(md_elems[0].key, "authorization") == 0);
   GPR_ASSERT(gpr_slice_str_cmp(md_elems[0].value, expected_md_value) == 0);
   GPR_ASSERT(user_data != NULL);
   GPR_ASSERT(strcmp((const char *)user_data, test_user_data) == 0);
@@ -751,15 +772,13 @@ static void on_jwt_creds_get_metadata_failure(grpc_exec_ctx *exec_ctx,
 static void test_jwt_creds_success(void) {
   char *json_key_string = test_json_key_str();
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_credentials *jwt_creds =
+  grpc_call_credentials *jwt_creds =
       grpc_service_account_jwt_access_credentials_create(
           json_key_string, grpc_max_auth_token_lifetime, NULL);
-  GPR_ASSERT(grpc_credentials_has_request_metadata(jwt_creds));
-  GPR_ASSERT(grpc_credentials_has_request_metadata_only(jwt_creds));
 
   /* First request: jwt_encode_and_sign should be called. */
   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
-  grpc_credentials_get_request_metadata(
+  grpc_call_credentials_get_request_metadata(
       &exec_ctx, jwt_creds, NULL, test_service_url,
       on_jwt_creds_get_metadata_success, (void *)test_user_data);
   grpc_exec_ctx_flush(&exec_ctx);
@@ -767,7 +786,7 @@ static void test_jwt_creds_success(void) {
   /* Second request: the cached token should be served directly. */
   grpc_jwt_encode_and_sign_set_override(
       encode_and_sign_jwt_should_not_be_called);
-  grpc_credentials_get_request_metadata(
+  grpc_call_credentials_get_request_metadata(
       &exec_ctx, jwt_creds, NULL, test_service_url,
       on_jwt_creds_get_metadata_success, (void *)test_user_data);
   grpc_exec_ctx_flush(&exec_ctx);
@@ -775,32 +794,30 @@ static void test_jwt_creds_success(void) {
   /* Third request: Different service url so jwt_encode_and_sign should be
      called again (no caching). */
   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_success);
-  grpc_credentials_get_request_metadata(
+  grpc_call_credentials_get_request_metadata(
       &exec_ctx, jwt_creds, NULL, other_test_service_url,
       on_jwt_creds_get_metadata_success, (void *)test_user_data);
   grpc_exec_ctx_flush(&exec_ctx);
 
   gpr_free(json_key_string);
-  grpc_credentials_unref(jwt_creds);
+  grpc_call_credentials_unref(jwt_creds);
   grpc_jwt_encode_and_sign_set_override(NULL);
 }
 
 static void test_jwt_creds_signing_failure(void) {
   char *json_key_string = test_json_key_str();
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
-  grpc_credentials *jwt_creds =
+  grpc_call_credentials *jwt_creds =
       grpc_service_account_jwt_access_credentials_create(
           json_key_string, grpc_max_auth_token_lifetime, NULL);
-  GPR_ASSERT(grpc_credentials_has_request_metadata(jwt_creds));
-  GPR_ASSERT(grpc_credentials_has_request_metadata_only(jwt_creds));
 
   grpc_jwt_encode_and_sign_set_override(encode_and_sign_jwt_failure);
-  grpc_credentials_get_request_metadata(
+  grpc_call_credentials_get_request_metadata(
       &exec_ctx, jwt_creds, NULL, test_service_url,
       on_jwt_creds_get_metadata_failure, (void *)test_user_data);
 
   gpr_free(json_key_string);
-  grpc_credentials_unref(jwt_creds);
+  grpc_call_credentials_unref(jwt_creds);
   grpc_jwt_encode_and_sign_set_override(NULL);
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -818,52 +835,39 @@ static void set_google_default_creds_env_var_with_file_contents(
   gpr_free(creds_file_name);
 }
 
-static grpc_credentials *composite_inner_creds(grpc_credentials *creds,
-                                               const char *inner_creds_type) {
-  size_t i;
-  grpc_composite_credentials *composite;
-  GPR_ASSERT(strcmp(creds->type, GRPC_CREDENTIALS_TYPE_COMPOSITE) == 0);
-  composite = (grpc_composite_credentials *)creds;
-  for (i = 0; i < composite->inner.num_creds; i++) {
-    grpc_credentials *c = composite->inner.creds_array[i];
-    if (strcmp(c->type, inner_creds_type) == 0) return c;
-  }
-  GPR_ASSERT(0); /* Not found. */
-}
-
 static void test_google_default_creds_auth_key(void) {
   grpc_service_account_jwt_access_credentials *jwt;
-  grpc_credentials *creds;
+  grpc_composite_channel_credentials *creds;
   char *json_key = test_json_key_str();
   grpc_flush_cached_google_default_credentials();
   set_google_default_creds_env_var_with_file_contents(
       "json_key_google_default_creds", json_key);
   gpr_free(json_key);
-  creds = grpc_google_default_credentials_create();
+  creds = (grpc_composite_channel_credentials *)
+      grpc_google_default_credentials_create();
   GPR_ASSERT(creds != NULL);
-  jwt = (grpc_service_account_jwt_access_credentials *)composite_inner_creds(
-      creds, GRPC_CREDENTIALS_TYPE_JWT);
+  jwt = (grpc_service_account_jwt_access_credentials *)creds->call_creds;
   GPR_ASSERT(
       strcmp(jwt->key.client_id,
              "777-abaslkan11hlb6nmim3bpspl31ud.apps.googleusercontent.com") ==
       0);
-  grpc_credentials_unref(creds);
+  grpc_channel_credentials_unref(&creds->base);
   gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
 }
 
 static void test_google_default_creds_access_token(void) {
   grpc_google_refresh_token_credentials *refresh;
-  grpc_credentials *creds;
+  grpc_composite_channel_credentials *creds;
   grpc_flush_cached_google_default_credentials();
   set_google_default_creds_env_var_with_file_contents(
       "refresh_token_google_default_creds", test_refresh_token_str);
-  creds = grpc_google_default_credentials_create();
+  creds = (grpc_composite_channel_credentials *)
+      grpc_google_default_credentials_create();
   GPR_ASSERT(creds != NULL);
-  refresh = (grpc_google_refresh_token_credentials *)composite_inner_creds(
-      creds, GRPC_CREDENTIALS_TYPE_OAUTH2);
+  refresh = (grpc_google_refresh_token_credentials *)creds->call_creds;
   GPR_ASSERT(strcmp(refresh->refresh_token.client_id,
                     "32555999999.apps.googleusercontent.com") == 0);
-  grpc_credentials_unref(creds);
+  grpc_channel_credentials_unref(&creds->base);
   gpr_setenv(GRPC_GOOGLE_CREDENTIALS_ENV_VAR, ""); /* Reset. */
 }
 
@@ -935,7 +939,7 @@ static void plugin_destroy(void *state) {
 }
 
 static void test_metadata_plugin_success(void) {
-  grpc_credentials *creds;
+  grpc_call_credentials *creds;
   plugin_state state = PLUGIN_INITIAL_STATE;
   grpc_metadata_credentials_plugin plugin;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
@@ -946,17 +950,17 @@ static void test_metadata_plugin_success(void) {
 
   creds = grpc_metadata_credentials_create_from_plugin(plugin, NULL);
   GPR_ASSERT(state == PLUGIN_INITIAL_STATE);
-  grpc_credentials_get_request_metadata(
+  grpc_call_credentials_get_request_metadata(
       &exec_ctx, creds, NULL, test_service_url,
       on_plugin_metadata_received_success, NULL);
   GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE);
-  grpc_credentials_release(creds);
+  grpc_call_credentials_release(creds);
   GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE);
   grpc_exec_ctx_finish(&exec_ctx);
 }
 
 static void test_metadata_plugin_failure(void) {
-  grpc_credentials *creds;
+  grpc_call_credentials *creds;
   plugin_state state = PLUGIN_INITIAL_STATE;
   grpc_metadata_credentials_plugin plugin;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
@@ -967,11 +971,11 @@ static void test_metadata_plugin_failure(void) {
 
   creds = grpc_metadata_credentials_create_from_plugin(plugin, NULL);
   GPR_ASSERT(state == PLUGIN_INITIAL_STATE);
-  grpc_credentials_get_request_metadata(
+  grpc_call_credentials_get_request_metadata(
       &exec_ctx, creds, NULL, test_service_url,
       on_plugin_metadata_received_failure, NULL);
   GPR_ASSERT(state == PLUGIN_GET_METADATA_CALLED_STATE);
-  grpc_credentials_release(creds);
+  grpc_call_credentials_release(creds);
   GPR_ASSERT(state == PLUGIN_DESTROY_CALLED_STATE);
   grpc_exec_ctx_finish(&exec_ctx);
 }
@@ -993,8 +997,9 @@ int main(int argc, char **argv) {
   test_oauth2_token_fetcher_creds_parsing_missing_token_lifetime();
   test_google_iam_creds();
   test_access_token_creds();
-  test_ssl_oauth2_composite_creds();
-  test_ssl_oauth2_google_iam_composite_creds();
+  test_channel_oauth2_composite_creds();
+  test_oauth2_google_iam_composite_creds();
+  test_channel_oauth2_google_iam_composite_creds();
   test_compute_engine_creds_success();
   test_compute_engine_creds_failure();
   test_refresh_token_creds_success();
diff --git a/test/core/security/fetch_oauth2.c b/test/core/security/fetch_oauth2.c
index 764d8da9b607ca2fa5cf4469602e37cf1b6ac07f..ee1178cbddf1d74f75b28e4407c02f27fc83042b 100644
--- a/test/core/security/fetch_oauth2.c
+++ b/test/core/security/fetch_oauth2.c
@@ -46,7 +46,7 @@
 #include "src/core/support/file.h"
 #include "test/core/security/oauth2_utils.h"
 
-static grpc_credentials *create_refresh_token_creds(
+static grpc_call_credentials *create_refresh_token_creds(
     const char *json_refresh_token_file_path) {
   int success;
   gpr_slice refresh_token =
@@ -60,7 +60,7 @@ static grpc_credentials *create_refresh_token_creds(
 }
 
 int main(int argc, char **argv) {
-  grpc_credentials *creds = NULL;
+  grpc_call_credentials *creds = NULL;
   char *json_key_file_path = NULL;
   char *json_refresh_token_file_path = NULL;
   char *token = NULL;
@@ -115,7 +115,7 @@ int main(int argc, char **argv) {
     printf("Got token: %s.\n", token);
     gpr_free(token);
   }
-  grpc_credentials_release(creds);
+  grpc_call_credentials_release(creds);
   gpr_cmdline_destroy(cl);
   grpc_shutdown();
   return 0;
diff --git a/test/core/security/oauth2_utils.c b/test/core/security/oauth2_utils.c
index f99d17059256f874b9ada6d90758f4e63435461c..fcfe8a637770a28617fc1762c83bf9620e4b3f4c 100644
--- a/test/core/security/oauth2_utils.c
+++ b/test/core/security/oauth2_utils.c
@@ -75,7 +75,8 @@ static void on_oauth2_response(grpc_exec_ctx *exec_ctx, void *user_data,
 
 static void do_nothing(grpc_exec_ctx *exec_ctx, void *unused, int success) {}
 
-char *grpc_test_fetch_oauth2_token_with_credentials(grpc_credentials *creds) {
+char *grpc_test_fetch_oauth2_token_with_credentials(
+    grpc_call_credentials *creds) {
   oauth2_request request;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   grpc_closure do_nothing_closure;
@@ -84,8 +85,8 @@ char *grpc_test_fetch_oauth2_token_with_credentials(grpc_credentials *creds) {
 
   grpc_closure_init(&do_nothing_closure, do_nothing, NULL);
 
-  grpc_credentials_get_request_metadata(&exec_ctx, creds, &request.pollset, "",
-                                        on_oauth2_response, &request);
+  grpc_call_credentials_get_request_metadata(&exec_ctx, creds, &request.pollset,
+                                             "", on_oauth2_response, &request);
 
   grpc_exec_ctx_finish(&exec_ctx);
 
diff --git a/test/core/security/oauth2_utils.h b/test/core/security/oauth2_utils.h
index 8082351b8a0cb20ee52ee3b18cebde9c0d0380c3..b35fe7987fc1ef92e9a23a79c56eb4cd15cafdb1 100644
--- a/test/core/security/oauth2_utils.h
+++ b/test/core/security/oauth2_utils.h
@@ -42,7 +42,8 @@ extern "C" {
 
 /* Fetch oauth2 access token with a credentials object. Does not take ownership.
    Returns NULL on a failure. The caller should call gpr_free on the token. */
-char *grpc_test_fetch_oauth2_token_with_credentials(grpc_credentials *creds);
+char *grpc_test_fetch_oauth2_token_with_credentials(
+    grpc_call_credentials *creds);
 
 #ifdef __cplusplus
 }
diff --git a/test/core/security/print_google_default_creds_token.c b/test/core/security/print_google_default_creds_token.c
index f207e0579473e919014bd59d3bb4598339981249..eb6372471537ca52159fce802444c80780d0291b 100644
--- a/test/core/security/print_google_default_creds_token.c
+++ b/test/core/security/print_google_default_creds_token.c
@@ -72,7 +72,7 @@ int main(int argc, char **argv) {
   int result = 0;
   grpc_exec_ctx exec_ctx = GRPC_EXEC_CTX_INIT;
   synchronizer sync;
-  grpc_credentials *creds = NULL;
+  grpc_channel_credentials *creds = NULL;
   char *service_url = "https://test.foo.google.com/Foo";
   gpr_cmdline *cl = gpr_cmdline_create("print_google_default_creds_token");
   gpr_cmdline_add_string(cl, "service_url",
@@ -91,9 +91,9 @@ int main(int argc, char **argv) {
   grpc_pollset_init(&sync.pollset);
   sync.is_done = 0;
 
-  grpc_credentials_get_request_metadata(&exec_ctx, creds, &sync.pollset,
-                                        service_url, on_metadata_response,
-                                        &sync);
+  grpc_call_credentials_get_request_metadata(
+      &exec_ctx, ((grpc_composite_channel_credentials *)creds)->call_creds,
+      &sync.pollset, service_url, on_metadata_response, &sync);
 
   gpr_mu_lock(GRPC_POLLSET_MU(&sync.pollset));
   while (!sync.is_done) {
@@ -107,7 +107,7 @@ int main(int argc, char **argv) {
   }
   gpr_mu_unlock(GRPC_POLLSET_MU(&sync.pollset));
 
-  grpc_credentials_release(creds);
+  grpc_channel_credentials_release(creds);
 
 end:
   gpr_cmdline_destroy(cl);
diff --git a/test/cpp/client/credentials_test.cc b/test/cpp/client/credentials_test.cc
index 743ad065d13a797cce016e5202e8104150f2b4c5..418a54439a9585853b1036d66bc43d46c2839ffd 100644
--- a/test/cpp/client/credentials_test.cc
+++ b/test/cpp/client/credentials_test.cc
@@ -46,8 +46,8 @@ class CredentialsTest : public ::testing::Test {
 };
 
 TEST_F(CredentialsTest, InvalidGoogleRefreshToken) {
-  std::shared_ptr<Credentials> bad1 = GoogleRefreshTokenCredentials("");
-  EXPECT_EQ(static_cast<Credentials*>(nullptr), bad1.get());
+  std::shared_ptr<CallCredentials> bad1 = GoogleRefreshTokenCredentials("");
+  EXPECT_EQ(static_cast<CallCredentials*>(nullptr), bad1.get());
 }
 
 }  // namespace testing
diff --git a/test/cpp/end2end/async_end2end_test.cc b/test/cpp/end2end/async_end2end_test.cc
index cfb6c21edc9e6ea7098b29a93a63cf2b15650877..74290c36d234c03be1d28067d69524431a93aa81 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -199,7 +199,7 @@ class AsyncEnd2endTest : public ::testing::TestWithParam<bool> {
 
   void ResetStub() {
     std::shared_ptr<Channel> channel =
-        CreateChannel(server_address_.str(), InsecureCredentials());
+        CreateChannel(server_address_.str(), InsecureChannelCredentials());
     stub_ = grpc::cpp::test::util::TestService::NewStub(channel);
   }
 
@@ -749,7 +749,7 @@ TEST_P(AsyncEnd2endTest, ServerCheckDone) {
 
 TEST_P(AsyncEnd2endTest, UnimplementedRpc) {
   std::shared_ptr<Channel> channel =
-      CreateChannel(server_address_.str(), InsecureCredentials());
+      CreateChannel(server_address_.str(), InsecureChannelCredentials());
   std::unique_ptr<grpc::cpp::test::util::UnimplementedService::Stub> stub;
   stub = grpc::cpp::test::util::UnimplementedService::NewStub(channel);
   EchoRequest send_request;
diff --git a/test/cpp/end2end/client_crash_test.cc b/test/cpp/end2end/client_crash_test.cc
index 058e6961666ccf9fa3be29dbe80270c654879a1d..116785bbf2c7259e1a2cca39e089da6bdb7ee803 100644
--- a/test/cpp/end2end/client_crash_test.cc
+++ b/test/cpp/end2end/client_crash_test.cc
@@ -74,7 +74,7 @@ class CrashTest : public ::testing::Test {
     }));
     GPR_ASSERT(server_);
     return grpc::cpp::test::util::TestService::NewStub(
-        CreateChannel(addr, InsecureCredentials()));
+        CreateChannel(addr, InsecureChannelCredentials()));
   }
 
   void KillServer() { server_.reset(); }
diff --git a/test/cpp/end2end/end2end_test.cc b/test/cpp/end2end/end2end_test.cc
index c5c71850265cb38f8feb684912a9c86b527108d8..6da933302c0128728986c4889dd644b91e8eb9a9 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -146,13 +146,13 @@ class TestAuthMetadataProcessor : public AuthMetadataProcessor {
 
   TestAuthMetadataProcessor(bool is_blocking) : is_blocking_(is_blocking) {}
 
-  std::shared_ptr<Credentials> GetCompatibleClientCreds() {
+  std::shared_ptr<CallCredentials> GetCompatibleClientCreds() {
     return MetadataCredentialsFromPlugin(
         std::unique_ptr<MetadataCredentialsPlugin>(
             new TestMetadataCredentialsPlugin(kGoodGuy, is_blocking_, true)));
   }
 
-  std::shared_ptr<Credentials> GetIncompatibleClientCreds() {
+  std::shared_ptr<CallCredentials> GetIncompatibleClientCreds() {
     return MetadataCredentialsFromPlugin(
         std::unique_ptr<MetadataCredentialsPlugin>(
             new TestMetadataCredentialsPlugin("Mr Hyde", is_blocking_, true)));
@@ -407,7 +407,7 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> {
     }
     EXPECT_TRUE(is_server_started_);
     ChannelArguments args;
-    auto channel_creds = InsecureCredentials();
+    auto channel_creds = InsecureChannelCredentials();
     if (GetParam().use_tls) {
       SslCredentialsOptions ssl_opts = {test_root_cert, "", ""};
       args.SetSslTargetNameOverride("foo.test.google.fr");
@@ -429,7 +429,7 @@ class End2endTest : public ::testing::TestWithParam<TestScenario> {
       builder.RegisterService(proxy_service_.get());
       proxy_server_ = builder.BuildAndStart();
 
-      channel_ = CreateChannel(proxyaddr.str(), InsecureCredentials());
+      channel_ = CreateChannel(proxyaddr.str(), InsecureChannelCredentials());
     }
 
     stub_ = grpc::cpp::test::util::TestService::NewStub(channel_);
@@ -575,6 +575,18 @@ void CancelRpc(ClientContext* context, int delay_us, TestServiceImpl* service) {
   context->TryCancel();
 }
 
+TEST_P(End2endTest, CancelRpcBeforeStart) {
+  ResetStub();
+  EchoRequest request;
+  EchoResponse response;
+  ClientContext context;
+  request.set_message("hello");
+  context.TryCancel();
+  Status s = stub_->Echo(&context, request, &response);
+  EXPECT_EQ("", response.message());
+  EXPECT_EQ(grpc::StatusCode::CANCELLED, s.error_code());
+}
+
 // Client cancels request stream after sending two messages
 TEST_P(End2endTest, ClientCancelsRequestStream) {
   ResetStub();
@@ -751,7 +763,8 @@ TEST_P(End2endTest, ChannelStateTimeout) {
   std::ostringstream server_address;
   server_address << "127.0.0.1:" << port;
   // Channel to non-existing server
-  auto channel = CreateChannel(server_address.str(), InsecureCredentials());
+  auto channel =
+      CreateChannel(server_address.str(), InsecureChannelCredentials());
   // Start IDLE
   EXPECT_EQ(GRPC_CHANNEL_IDLE, channel->GetState(true));
 
@@ -971,33 +984,6 @@ TEST_P(SecureEnd2endTest, SimpleRpcWithHost) {
   EXPECT_TRUE(s.ok());
 }
 
-// rpc and stream should fail on bad credentials.
-TEST_P(SecureEnd2endTest, BadCredentials) {
-  std::shared_ptr<Credentials> bad_creds = GoogleRefreshTokenCredentials("");
-  EXPECT_EQ(static_cast<Credentials*>(nullptr), bad_creds.get());
-  std::shared_ptr<Channel> channel =
-      CreateChannel(server_address_.str(), bad_creds);
-  std::unique_ptr<grpc::cpp::test::util::TestService::Stub> stub(
-      grpc::cpp::test::util::TestService::NewStub(channel));
-  EchoRequest request;
-  EchoResponse response;
-  ClientContext context;
-  request.set_message("Hello");
-
-  Status s = stub->Echo(&context, request, &response);
-  EXPECT_EQ("", response.message());
-  EXPECT_FALSE(s.ok());
-  EXPECT_EQ(StatusCode::INVALID_ARGUMENT, s.error_code());
-  EXPECT_EQ("Invalid credentials.", s.error_message());
-
-  ClientContext context2;
-  auto stream = stub->BidiStream(&context2);
-  s = stream->Finish();
-  EXPECT_FALSE(s.ok());
-  EXPECT_EQ(StatusCode::INVALID_ARGUMENT, s.error_code());
-  EXPECT_EQ("Invalid credentials.", s.error_message());
-}
-
 bool MetadataContains(
     const std::multimap<grpc::string_ref, grpc::string_ref>& metadata,
     const grpc::string& key, const grpc::string& value) {
@@ -1055,7 +1041,7 @@ TEST_P(SecureEnd2endTest, SetPerCallCredentials) {
   EchoRequest request;
   EchoResponse response;
   ClientContext context;
-  std::shared_ptr<Credentials> creds =
+  std::shared_ptr<CallCredentials> creds =
       GoogleIAMCredentials("fake_token", "fake_selector");
   context.set_credentials(creds);
   request.set_message("Hello");
@@ -1072,30 +1058,15 @@ TEST_P(SecureEnd2endTest, SetPerCallCredentials) {
                                "fake_selector"));
 }
 
-TEST_P(SecureEnd2endTest, InsecurePerCallCredentials) {
-  ResetStub();
-  EchoRequest request;
-  EchoResponse response;
-  ClientContext context;
-  std::shared_ptr<Credentials> creds = InsecureCredentials();
-  context.set_credentials(creds);
-  request.set_message("Hello");
-  request.mutable_param()->set_echo_metadata(true);
-
-  Status s = stub_->Echo(&context, request, &response);
-  EXPECT_EQ(StatusCode::CANCELLED, s.error_code());
-  EXPECT_EQ("Failed to set credentials to rpc.", s.error_message());
-}
-
 TEST_P(SecureEnd2endTest, OverridePerCallCredentials) {
   ResetStub();
   EchoRequest request;
   EchoResponse response;
   ClientContext context;
-  std::shared_ptr<Credentials> creds1 =
+  std::shared_ptr<CallCredentials> creds1 =
       GoogleIAMCredentials("fake_token1", "fake_selector1");
   context.set_credentials(creds1);
-  std::shared_ptr<Credentials> creds2 =
+  std::shared_ptr<CallCredentials> creds2 =
       GoogleIAMCredentials("fake_token2", "fake_selector2");
   context.set_credentials(creds2);
   request.set_message("Hello");
diff --git a/test/cpp/end2end/generic_end2end_test.cc b/test/cpp/end2end/generic_end2end_test.cc
index 6a4691672871520e984f510b4832a2e61198cc1c..082119d6d52f0cae48c0b86b6a79825bd0e5c82b 100644
--- a/test/cpp/end2end/generic_end2end_test.cc
+++ b/test/cpp/end2end/generic_end2end_test.cc
@@ -120,7 +120,7 @@ class GenericEnd2endTest : public ::testing::Test {
 
   void ResetStub() {
     std::shared_ptr<Channel> channel =
-        CreateChannel(server_address_.str(), InsecureCredentials());
+        CreateChannel(server_address_.str(), InsecureChannelCredentials());
     generic_stub_.reset(new GenericStub(channel));
   }
 
diff --git a/test/cpp/end2end/mock_test.cc b/test/cpp/end2end/mock_test.cc
index 80057d893e10071e9bccbeeaf722db1c2ea35daf..bd34cfba671972f87fd4da6b38715a74d8fffd5a 100644
--- a/test/cpp/end2end/mock_test.cc
+++ b/test/cpp/end2end/mock_test.cc
@@ -244,7 +244,7 @@ class MockTest : public ::testing::Test {
 
   void ResetStub() {
     std::shared_ptr<Channel> channel =
-        CreateChannel(server_address_.str(), InsecureCredentials());
+        CreateChannel(server_address_.str(), InsecureChannelCredentials());
     stub_ = grpc::cpp::test::util::TestService::NewStub(channel);
   }
 
diff --git a/test/cpp/end2end/server_crash_test_client.cc b/test/cpp/end2end/server_crash_test_client.cc
index 17869362c2e70d81bd7807b9ff0a72ef55e76301..2baefcbf42d06ce7bcc04edb767d3bf6427ea923 100644
--- a/test/cpp/end2end/server_crash_test_client.cc
+++ b/test/cpp/end2end/server_crash_test_client.cc
@@ -58,7 +58,7 @@ using namespace gflags;
 int main(int argc, char** argv) {
   ParseCommandLineFlags(&argc, &argv, true);
   auto stub = grpc::cpp::test::util::TestService::NewStub(
-      grpc::CreateChannel(FLAGS_address, grpc::InsecureCredentials()));
+      grpc::CreateChannel(FLAGS_address, grpc::InsecureChannelCredentials()));
 
   EchoRequest request;
   EchoResponse response;
diff --git a/test/cpp/end2end/shutdown_test.cc b/test/cpp/end2end/shutdown_test.cc
index 0549bb8b5f7f7d46b06a61a20a575f301fba00fe..b1b18b2a7f4b30eb55d1dc274f10e7fc2f9ea3a0 100644
--- a/test/cpp/end2end/shutdown_test.cc
+++ b/test/cpp/end2end/shutdown_test.cc
@@ -93,7 +93,7 @@ class ShutdownTest : public ::testing::Test {
 
   void ResetStub() {
     string target = "dns:localhost:" + to_string(port_);
-    channel_ = CreateChannel(target, InsecureCredentials());
+    channel_ = CreateChannel(target, InsecureChannelCredentials());
     stub_ = grpc::cpp::test::util::TestService::NewStub(channel_);
   }
 
diff --git a/test/cpp/end2end/streaming_throughput_test.cc b/test/cpp/end2end/streaming_throughput_test.cc
index d4ab1486ccbbde7d6f266d4c8179b60ec2893339..b7e103a1ae0bf99a4095e48250867261e6ec0521 100644
--- a/test/cpp/end2end/streaming_throughput_test.cc
+++ b/test/cpp/end2end/streaming_throughput_test.cc
@@ -160,7 +160,7 @@ class End2endTest : public ::testing::Test {
 
   void ResetStub() {
     std::shared_ptr<Channel> channel =
-        CreateChannel(server_address_.str(), InsecureCredentials());
+        CreateChannel(server_address_.str(), InsecureChannelCredentials());
     stub_ = grpc::cpp::test::util::TestService::NewStub(channel);
   }
 
diff --git a/test/cpp/end2end/thread_stress_test.cc b/test/cpp/end2end/thread_stress_test.cc
index 75a07d89c5d5c0cdedf5e1c57e5e2ca14f035fee..fb82b9613596e63543edc6373484360e2ab39567 100644
--- a/test/cpp/end2end/thread_stress_test.cc
+++ b/test/cpp/end2end/thread_stress_test.cc
@@ -190,7 +190,7 @@ class End2endTest : public ::testing::Test {
 
   void ResetStub() {
     std::shared_ptr<Channel> channel =
-        CreateChannel(server_address_.str(), InsecureCredentials());
+        CreateChannel(server_address_.str(), InsecureChannelCredentials());
     stub_ = grpc::cpp::test::util::TestService::NewStub(channel);
   }
 
diff --git a/test/cpp/end2end/zookeeper_test.cc b/test/cpp/end2end/zookeeper_test.cc
index d4c7f0489fd09a3cdd47818375185e412c5752fe..e88c0f9c68a870b9bebf015ad073c0f1fba2f2f1 100644
--- a/test/cpp/end2end/zookeeper_test.cc
+++ b/test/cpp/end2end/zookeeper_test.cc
@@ -157,7 +157,7 @@ class ZookeeperTest : public ::testing::Test {
 
   void ResetStub() {
     string target = "zookeeper://" + zookeeper_address_ + "/test";
-    channel_ = CreateChannel(target, InsecureCredentials());
+    channel_ = CreateChannel(target, InsecureChannelCredentials());
     stub_ = std::move(grpc::cpp::test::util::TestService::NewStub(channel_));
   }
 
diff --git a/test/cpp/interop/client_helper.cc b/test/cpp/interop/client_helper.cc
index 61b46d25aa041a08f32dd901ec8b82b1ee02f786..5caf0f2d1d0242bfaec238bce655292477bf4bdc 100644
--- a/test/cpp/interop/client_helper.cc
+++ b/test/cpp/interop/client_helper.cc
@@ -76,11 +76,11 @@ grpc::string GetServiceAccountJsonKey() {
 }
 
 grpc::string GetOauth2AccessToken() {
-  std::shared_ptr<Credentials> creds = GoogleComputeEngineCredentials();
-  SecureCredentials* secure_creds =
-      dynamic_cast<SecureCredentials*>(creds.get());
+  std::shared_ptr<CallCredentials> creds = GoogleComputeEngineCredentials();
+  SecureCallCredentials* secure_creds =
+      dynamic_cast<SecureCallCredentials*>(creds.get());
   GPR_ASSERT(secure_creds != nullptr);
-  grpc_credentials* c_creds = secure_creds->GetRawCreds();
+  grpc_call_credentials* c_creds = secure_creds->GetRawCreds();
   char* token = grpc_test_fetch_oauth2_token_with_credentials(c_creds);
   GPR_ASSERT(token != nullptr);
   gpr_log(GPR_INFO, "Get raw oauth2 access token: %s", token);
@@ -98,13 +98,13 @@ std::shared_ptr<Channel> CreateChannelForTestCase(
            FLAGS_server_port);
 
   if (test_case == "compute_engine_creds") {
-    std::shared_ptr<Credentials> creds;
+    std::shared_ptr<CallCredentials> creds;
     GPR_ASSERT(FLAGS_use_tls);
     creds = GoogleComputeEngineCredentials();
     return CreateTestChannel(host_port, FLAGS_server_host_override,
                              FLAGS_use_tls, !FLAGS_use_test_ca, creds);
   } else if (test_case == "jwt_token_creds") {
-    std::shared_ptr<Credentials> creds;
+    std::shared_ptr<CallCredentials> creds;
     GPR_ASSERT(FLAGS_use_tls);
     grpc::string json_key = GetServiceAccountJsonKey();
     std::chrono::seconds token_lifetime = std::chrono::hours(1);
@@ -114,7 +114,7 @@ std::shared_ptr<Channel> CreateChannelForTestCase(
                              FLAGS_use_tls, !FLAGS_use_test_ca, creds);
   } else if (test_case == "oauth2_auth_token") {
     grpc::string raw_token = GetOauth2AccessToken();
-    std::shared_ptr<Credentials> creds = AccessTokenCredentials(raw_token);
+    std::shared_ptr<CallCredentials> creds = AccessTokenCredentials(raw_token);
     return CreateTestChannel(host_port, FLAGS_server_host_override,
                              FLAGS_use_tls, !FLAGS_use_test_ca, creds);
   } else {
diff --git a/test/cpp/interop/interop_client.cc b/test/cpp/interop/interop_client.cc
index 46a5255e4c62d5f9c10f292060a9d73be7791340..6340007fa4bc5b6bca6136b2c58fd75aeb11b401 100644
--- a/test/cpp/interop/interop_client.cc
+++ b/test/cpp/interop/interop_client.cc
@@ -244,7 +244,7 @@ void InteropClient::DoPerRpcCreds(const grpc::string& json_key) {
 
   ClientContext context;
   std::chrono::seconds token_lifetime = std::chrono::hours(1);
-  std::shared_ptr<Credentials> creds =
+  std::shared_ptr<CallCredentials> creds =
       ServiceAccountJWTAccessCredentials(json_key, token_lifetime.count());
 
   context.set_credentials(creds);
diff --git a/test/cpp/interop/stress_interop_client.cc b/test/cpp/interop/stress_interop_client.cc
index f8c55cf795917023d42f01a2058b231a0374a503..3be2571493476b7cff0603ea894794b86fd21d45 100644
--- a/test/cpp/interop/stress_interop_client.cc
+++ b/test/cpp/interop/stress_interop_client.cc
@@ -89,9 +89,9 @@ StressTestInteropClient::StressTestInteropClient(
       test_duration_secs_(test_duration_secs),
       sleep_duration_ms_(sleep_duration_ms) {
   // TODO(sreek): This will change once we add support for other tests
-  // that won't work with InsecureCredentials()
+  // that won't work with InsecureChannelCredentials()
   std::shared_ptr<Channel> channel(
-      CreateChannel(server_address, InsecureCredentials()));
+      CreateChannel(server_address, InsecureChannelCredentials()));
   interop_client_.reset(new InteropClient(channel, false));
 }
 
diff --git a/test/cpp/interop/stress_test.cc b/test/cpp/interop/stress_test.cc
index 5d1419728e4ca7d46ddc809a7d828a12e1f2860d..018f4ab4f71eeb556b21cff6992b1cbe5111db25 100644
--- a/test/cpp/interop/stress_test.cc
+++ b/test/cpp/interop/stress_test.cc
@@ -41,6 +41,7 @@
 #include <grpc/support/time.h>
 #include <grpc++/create_channel.h>
 #include <grpc++/grpc++.h>
+#include <grpc++/impl/thd.h>
 
 #include "test/cpp/interop/interop_client.h"
 #include "test/cpp/interop/stress_interop_client.h"
@@ -80,7 +81,6 @@ DEFINE_string(test_cases, "",
 
 using std::make_pair;
 using std::pair;
-using std::thread;
 using std::vector;
 
 using grpc::testing::kTestCaseList;
@@ -202,7 +202,7 @@ int main(int argc, char** argv) {
 
   gpr_log(GPR_INFO, "Starting test(s)..");
 
-  vector<thread> test_threads;
+  vector<grpc::thread> test_threads;
   int thread_idx = 0;
   for (auto it = server_addresses.begin(); it != server_addresses.end(); it++) {
     StressTestInteropClient* client = new StressTestInteropClient(
@@ -210,7 +210,7 @@ int main(int argc, char** argv) {
         FLAGS_sleep_duration_ms);
 
     test_threads.emplace_back(
-        thread(&StressTestInteropClient::MainLoop, client));
+        grpc::thread(&StressTestInteropClient::MainLoop, client));
   }
 
   for (auto it = test_threads.begin(); it != test_threads.end(); it++) {
diff --git a/test/cpp/qps/driver.cc b/test/cpp/qps/driver.cc
index 2c6247deea16e28b6e88d49b05eef929ea4b1926..67bdcb2f32ca033b019a4671ca78c912cc7e9208 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -162,7 +162,7 @@ std::unique_ptr<ScenarioResult> RunScenario(
   auto* servers = new ServerData[num_servers];
   for (size_t i = 0; i < num_servers; i++) {
     servers[i].stub = WorkerService::NewStub(
-        CreateChannel(workers[i], InsecureCredentials()));
+        CreateChannel(workers[i], InsecureChannelCredentials()));
     ServerArgs args;
     result_server_config = server_config;
     *args.mutable_setup() = server_config;
@@ -189,7 +189,7 @@ std::unique_ptr<ScenarioResult> RunScenario(
   auto* clients = new ClientData[num_clients];
   for (size_t i = 0; i < num_clients; i++) {
     clients[i].stub = WorkerService::NewStub(
-        CreateChannel(workers[i + num_servers], InsecureCredentials()));
+        CreateChannel(workers[i + num_servers], InsecureChannelCredentials()));
     ClientArgs args;
     result_client_config = client_config;
     *args.mutable_setup() = client_config;
diff --git a/test/cpp/qps/report.h b/test/cpp/qps/report.h
index 78779231d38af3fbcfb90cc2b25a35f1fbbed104..5caf3fe69a290c654b92d1c348c5ca5737aaf3b2 100644
--- a/test/cpp/qps/report.h
+++ b/test/cpp/qps/report.h
@@ -115,8 +115,8 @@ class PerfDbReporter : public Reporter {
         test_name_(test_name),
         sys_info_(sys_info),
         tag_(tag) {
-    perf_db_client_.init(
-        grpc::CreateChannel(server_address, grpc::InsecureCredentials()));
+    perf_db_client_.init(grpc::CreateChannel(
+        server_address, grpc::InsecureChannelCredentials()));
   }
   ~PerfDbReporter() GRPC_OVERRIDE { SendData(); };
 
diff --git a/test/cpp/util/cli_call_test.cc b/test/cpp/util/cli_call_test.cc
index 9c8d59987e03557e7b86071c48e6b57711ddbd4b..32cd8e41030095f2df25342cdb4edb6265cbd6ea 100644
--- a/test/cpp/util/cli_call_test.cc
+++ b/test/cpp/util/cli_call_test.cc
@@ -89,7 +89,8 @@ class CliCallTest : public ::testing::Test {
   void TearDown() GRPC_OVERRIDE { server_->Shutdown(); }
 
   void ResetStub() {
-    channel_ = CreateChannel(server_address_.str(), InsecureCredentials());
+    channel_ =
+        CreateChannel(server_address_.str(), InsecureChannelCredentials());
     stub_ = grpc::cpp::test::util::TestService::NewStub(channel_);
   }
 
diff --git a/test/cpp/util/create_test_channel.cc b/test/cpp/util/create_test_channel.cc
index f0d5bfc7ebc1ba0cf28849a8174731771acacaa8..0cd9f9e76738c459ecf26434a502a754bad812a6 100644
--- a/test/cpp/util/create_test_channel.cc
+++ b/test/cpp/util/create_test_channel.cc
@@ -58,13 +58,14 @@ namespace grpc {
 std::shared_ptr<Channel> CreateTestChannel(
     const grpc::string& server, const grpc::string& override_hostname,
     bool enable_ssl, bool use_prod_roots,
-    const std::shared_ptr<Credentials>& creds) {
+    const std::shared_ptr<CallCredentials>& creds) {
   ChannelArguments channel_args;
   if (enable_ssl) {
     const char* roots_certs = use_prod_roots ? "" : test_root_cert;
     SslCredentialsOptions ssl_opts = {roots_certs, "", ""};
 
-    std::shared_ptr<Credentials> channel_creds = SslCredentials(ssl_opts);
+    std::shared_ptr<ChannelCredentials> channel_creds =
+        SslCredentials(ssl_opts);
 
     if (!server.empty() && !override_hostname.empty()) {
       channel_args.SetSslTargetNameOverride(override_hostname);
@@ -72,11 +73,11 @@ std::shared_ptr<Channel> CreateTestChannel(
     const grpc::string& connect_to =
         server.empty() ? override_hostname : server;
     if (creds.get()) {
-      channel_creds = CompositeCredentials(creds, channel_creds);
+      channel_creds = CompositeChannelCredentials(channel_creds, creds);
     }
     return CreateCustomChannel(connect_to, channel_creds, channel_args);
   } else {
-    return CreateChannel(server, InsecureCredentials());
+    return CreateChannel(server, InsecureChannelCredentials());
   }
 }
 
@@ -84,7 +85,7 @@ std::shared_ptr<Channel> CreateTestChannel(
     const grpc::string& server, const grpc::string& override_hostname,
     bool enable_ssl, bool use_prod_roots) {
   return CreateTestChannel(server, override_hostname, enable_ssl,
-                           use_prod_roots, std::shared_ptr<Credentials>());
+                           use_prod_roots, std::shared_ptr<CallCredentials>());
 }
 
 // Shortcut for end2end and interop tests.
diff --git a/test/cpp/util/create_test_channel.h b/test/cpp/util/create_test_channel.h
index a4750689a0c826fc8cfc46765eec6e2b02c2fbf9..b50d653de3b9d2744949709acd7eaf5c3f5e5492 100644
--- a/test/cpp/util/create_test_channel.h
+++ b/test/cpp/util/create_test_channel.h
@@ -51,7 +51,7 @@ std::shared_ptr<Channel> CreateTestChannel(
 std::shared_ptr<Channel> CreateTestChannel(
     const grpc::string& server, const grpc::string& override_hostname,
     bool enable_ssl, bool use_prod_roots,
-    const std::shared_ptr<Credentials>& creds);
+    const std::shared_ptr<CallCredentials>& creds);
 
 }  // namespace grpc
 
diff --git a/test/cpp/util/grpc_cli.cc b/test/cpp/util/grpc_cli.cc
index 334b6efb6a54ef0745d7c866d18903f1723b935a..3f40b242fc00fd7abbd2a0dae6be7544f95f068f 100644
--- a/test/cpp/util/grpc_cli.cc
+++ b/test/cpp/util/grpc_cli.cc
@@ -148,9 +148,9 @@ int main(int argc, char** argv) {
   std::stringstream input_stream;
   input_stream << input_file.rdbuf();
 
-  std::shared_ptr<grpc::Credentials> creds;
+  std::shared_ptr<grpc::ChannelCredentials> creds;
   if (!FLAGS_enable_ssl) {
-    creds = grpc::InsecureCredentials();
+    creds = grpc::InsecureChannelCredentials();
   } else {
     if (FLAGS_use_auth) {
       creds = grpc::GoogleDefaultCredentials();
diff --git a/tools/buildgen/plugins/transitive_dependencies.py b/tools/buildgen/plugins/transitive_dependencies.py
new file mode 100644
index 0000000000000000000000000000000000000000..c2d3da3a3b264dd95256fb7c24e2a9a554651d06
--- /dev/null
+++ b/tools/buildgen/plugins/transitive_dependencies.py
@@ -0,0 +1,63 @@
+# Copyright 2015, Google Inc.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+#     * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#     * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+#     * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""Buildgen transitive dependencies
+
+This takes the list of libs, node_modules, and targets from our
+yaml dictionary, and adds to each the transitive closure
+of the list of dependencies.
+
+"""
+
+def get_lib(libs, name):
+  return next(lib for lib in libs if lib['name']==name)
+
+def transitive_deps(lib, libs):
+  if 'deps' in lib:
+    # Recursively call transitive_deps on each dependency, and take the union
+    return set.union(set(lib['deps']),
+                     *[set(transitive_deps(get_lib(libs, dep), libs))
+                       for dep in lib['deps']])
+  else:
+    return set()
+
+def mako_plugin(dictionary):
+  """The exported plugin code for transitive_dependencies.
+
+  Each item in libs, node_modules, and targets can have a deps list.
+  We add a transitive_deps property to each with the transitive closure
+  of those dependency lists.
+  """
+  libs = dictionary.get('libs')
+  node_modules = dictionary.get('node_modules')
+  targets = dictionary.get('targets')
+
+  for target_list in (libs, node_modules, targets):
+    for target in target_list:
+      target['transitive_deps'] = transitive_deps(target, libs)
diff --git a/tools/codegen/core/gen_chttp2_stream_lists.py b/tools/codegen/core/gen_chttp2_stream_lists.py
deleted file mode 100644
index b28b04f643122b019e912540f228c8ed20be9eeb..0000000000000000000000000000000000000000
--- a/tools/codegen/core/gen_chttp2_stream_lists.py
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/tools/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 5d592c8e0aefdc4957deb9d59217bf34849630c2..f07718515a64010c25eeb267208850fc754ef14e 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -40,7 +40,7 @@ PROJECT_NAME           = "GRPC C++"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.11.0.0
+PROJECT_NUMBER         = 0.12.0.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.c++.internal b/tools/doxygen/Doxyfile.c++.internal
index bbd1706fb059f6a03e6e6fdd1b5fc64a26a5433c..11aaa379cec55c10d2c2af3b3bae9cba6e681b24 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -40,7 +40,7 @@ PROJECT_NAME           = "GRPC C++"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.11.0.0
+PROJECT_NUMBER         = 0.12.0.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.core b/tools/doxygen/Doxyfile.core
index beb0128e41a2a847b5c75fb7e121fde23a00de71..e411abf300547e3144ea31bde8c556ad6f37b78b 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -40,7 +40,7 @@ PROJECT_NAME           = "GRPC Core"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.11.0.0
+PROJECT_NUMBER         = 0.12.0.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/doxygen/Doxyfile.core.internal b/tools/doxygen/Doxyfile.core.internal
index 4ce48b4790d4229f2b5feabe39139fd478be07ac..f0ec37b089c48609f113c97a6b847e2e363f7002 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -40,7 +40,7 @@ PROJECT_NAME           = "GRPC Core"
 # could be handy for archiving the generated documentation or if some version
 # control system is used.
 
-PROJECT_NUMBER         = 0.11.0.0
+PROJECT_NUMBER         = 0.12.0.0
 
 # Using the PROJECT_BRIEF tag one can provide an optional one line description
 # for a project that appears at the top of each page and should give viewer a
diff --git a/tools/http2_interop/http2_interop.test b/tools/http2_interop/http2_interop.test
deleted file mode 100755
index 0700763dc3386b03bbbf19ef4c241702ccf187ad..0000000000000000000000000000000000000000
Binary files a/tools/http2_interop/http2_interop.test and /dev/null differ
diff --git a/tools/jenkins/run_interop.sh b/tools/jenkins/run_interop.sh
index 5dd477ed77ac2ee927fff38eaaeefc3f8bb7e869..a424aea7fc47641fefd5a39c96d987ea6e569a0a 100755
--- a/tools/jenkins/run_interop.sh
+++ b/tools/jenkins/run_interop.sh
@@ -34,4 +34,4 @@ set -ex
 # Enter the gRPC repo root
 cd $(dirname $0)/../..
 
-tools/run_tests/run_interop_tests.py -l all -s all --cloud_to_prod --cloud_to_prod_auth --use_docker -t -j 12 $@ || true
+tools/run_tests/run_interop_tests.py -l all -s all --cloud_to_prod --cloud_to_prod_auth --use_docker --http2_interop -t -j 12 $@ || true
diff --git a/tools/run_tests/port_server.py b/tools/run_tests/port_server.py
index 3b85486ebfe599732f38f1db2756db9b03edc2e4..14e82b601eadbef7062397a2c33c791bff43318c 100755
--- a/tools/run_tests/port_server.py
+++ b/tools/run_tests/port_server.py
@@ -42,7 +42,7 @@ import time
 # increment this number whenever making a change to ensure that
 # the changes are picked up by running CI servers
 # note that all changes must be backwards compatible
-_MY_VERSION = 5
+_MY_VERSION = 7
 
 
 if len(sys.argv) == 2 and sys.argv[1] == 'dump_version':
diff --git a/tools/run_tests/run_interop_tests.py b/tools/run_tests/run_interop_tests.py
index 1686942b0ae9eb2ce467922fa75c7027ed60ed14..2634164a2150ea0a7e1cc06d40e9b17f6eab53ee 100755
--- a/tools/run_tests/run_interop_tests.py
+++ b/tools/run_tests/run_interop_tests.py
@@ -624,7 +624,9 @@ try:
                                            docker_image=docker_images.get(str(language)))
           jobs.append(test_job)
           
-    if args.http2_interop:
+    # TODO(carl-mastrangelo): Currently prod TLS terminators aren't spec compliant. Reenable
+    # this once a better solution is in place.
+    if args.http2_interop and False:
       for test_case in _HTTP2_TEST_CASES:
         test_job = cloud_to_prod_jobspec(http2Interop, test_case,
                                          docker_image=docker_images.get(str(http2Interop)))
@@ -660,6 +662,9 @@ try:
           
     if args.http2_interop:
       for test_case in _HTTP2_TEST_CASES:
+        if server_name == "go":
+          # TODO(carl-mastrangelo): Reenable after https://github.com/grpc/grpc-go/issues/434
+          continue 
         test_job = cloud_to_cloud_jobspec(http2Interop,
                                           test_case,
                                           server_name,
diff --git a/tools/run_tests/run_tests.py b/tools/run_tests/run_tests.py
index 85c73d6fbd20eb9dca23061d3227e8d2c3c5523c..ab2b71b80e0cb8c27fcd9f3cefbedb9fd247d22b 100755
--- a/tools/run_tests/run_tests.py
+++ b/tools/run_tests/run_tests.py
@@ -749,7 +749,8 @@ def _start_port_server(port_server_port):
     running = False
   if running:
     current_version = int(subprocess.check_output(
-        [sys.executable, 'tools/run_tests/port_server.py', 'dump_version']))
+        [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
+         'dump_version']))
     print 'my port server is version %d' % current_version
     running = (version >= current_version)
     if not running:
@@ -760,13 +761,18 @@ def _start_port_server(port_server_port):
     fd, logfile = tempfile.mkstemp()
     os.close(fd)
     print 'starting port_server, with log file %s' % logfile
-    args = [sys.executable, 'tools/run_tests/port_server.py', '-p', '%d' % port_server_port, '-l', logfile]
+    args = [sys.executable, os.path.abspath('tools/run_tests/port_server.py'),
+            '-p', '%d' % port_server_port, '-l', logfile]
     env = dict(os.environ)
     env['BUILD_ID'] = 'pleaseDontKillMeJenkins'
     if platform.system() == 'Windows':
+      # Working directory of port server needs to be outside of Jenkins
+      # workspace to prevent file lock issues.
+      tempdir = tempfile.mkdtemp()
       port_server = subprocess.Popen(
           args,
           env=env,
+          cwd=tempdir,
           creationflags = 0x00000008, # detached process
           close_fds=True)
     else: