Merge pull request #3993 from ctiller/new_op

Core transport & call cleanup
diff --git a/Makefile b/Makefile
index 53d0696..546bc68 100644
--- a/Makefile
+++ b/Makefile
@@ -312,7 +312,7 @@
 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 502b9d7..1883f73 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 bd93a16..c40a6bb 100644
--- a/build.yaml
+++ b/build.yaml
@@ -5,7 +5,7 @@
   '#': The public version number of the library.
   version:
     major: 0
-    minor: 11
+    minor: 12
     micro: 0
     build: 0
 filegroups:
@@ -2224,3 +2224,19 @@
   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/grpc-auth-support.md b/doc/grpc-auth-support.md
index 800fbed..b210ff1 100644
--- a/doc/grpc-auth-support.md
+++ b/doc/grpc-auth-support.md
@@ -36,9 +36,9 @@
 ```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 @@
 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 8649213..53cc47b 100644
--- a/doc/interop-test-descriptions.md
+++ b/doc/interop-test-descriptions.md
@@ -4,7 +4,7 @@
 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 78de014..cd1cddb 100644
--- a/examples/cpp/cpptutorial.md
+++ b/examples/cpp/cpptutorial.md
@@ -245,7 +245,7 @@
 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 b16c084..7a7194d 100644
--- a/examples/cpp/helloworld/README.md
+++ b/examples/cpp/helloworld/README.md
@@ -94,7 +94,7 @@
   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 923c8ff..3501426 100644
--- a/examples/cpp/helloworld/greeter_async_client.cc
+++ b/examples/cpp/helloworld/greeter_async_client.cc
@@ -114,9 +114,9 @@
   // 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 6cd8353..bf3b63c 100644
--- a/examples/cpp/helloworld/greeter_client.cc
+++ b/examples/cpp/helloworld/greeter_client.cc
@@ -84,9 +84,9 @@
   // 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 85173a3..b9abe72 100644
--- a/examples/cpp/route_guide/route_guide_client.cc
+++ b/examples/cpp/route_guide/route_guide_client.cc
@@ -234,7 +234,8 @@
   // 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/python/helloworld/greeter_server.py b/examples/python/helloworld/greeter_server.py
index 1514d8f..2cde5ad 100644
--- a/examples/python/helloworld/greeter_server.py
+++ b/examples/python/helloworld/greeter_server.py
@@ -50,7 +50,7 @@
     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 60c816d..d6d72a9 100644
--- a/include/grpc++/channel.h
+++ b/include/grpc++/channel.h
@@ -47,8 +47,8 @@
 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 7046f93..5c6f432 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 @@
 
 class Channel;
 class CompletionQueue;
-class Credentials;
+class CallCredentials;
 class RpcMethod;
 template <class R>
 class ClientReader;
@@ -244,7 +245,7 @@
   /// 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 @@
 
   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 196d292..aff9c29 100644
--- a/include/grpc++/create_channel.h
+++ b/include/grpc++/create_channel.h
@@ -49,7 +49,8 @@
 /// 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 @@
 /// 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 ff41bc5..56827c0 100644
--- a/include/grpc++/security/credentials.h
+++ b/include/grpc++/security/credentials.h
@@ -45,35 +45,58 @@
 namespace grpc {
 class ChannelArguments;
 class Channel;
-class SecureCredentials;
+class SecureChannelCredentials;
+class CallCredentials;
+class SecureCallCredentials;
 
-/// 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.
+/// 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;
+  ~ChannelCredentials() GRPC_OVERRIDE;
+
+ protected:
+  friend std::shared_ptr<ChannelCredentials> CompositeChannelCredentials(
+      const std::shared_ptr<ChannelCredentials>& channel_creds,
+      const std::shared_ptr<CallCredentials>& call_creds);
+
+  virtual SecureChannelCredentials* AsSecureCredentials() = 0;
+
+ private:
+  friend std::shared_ptr<Channel> CreateCustomChannel(
+      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<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;
+  friend std::shared_ptr<CallCredentials> CompositeCallCredentials(
+      const std::shared_ptr<CallCredentials>& creds1,
+      const std::shared_ptr<CallCredentials>& creds2);
 
- private:
-  friend std::shared_ptr<Channel> CreateCustomChannel(
-      const grpc::string& target, const std::shared_ptr<Credentials>& creds,
-      const ChannelArguments& args);
-
-  virtual std::shared_ptr<Channel> CreateChannel(
-      const grpc::string& target, const ChannelArguments& args) = 0;
+  virtual SecureCallCredentials* AsSecureCredentials() = 0;
 };
 
 /// Options used to build SslCredentials.
@@ -106,10 +129,10 @@
 /// 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 @@
 /// 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 @@
 /// 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 @@
 /// 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 @@
 /// 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 @@
       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 4da76a8..cf8eab3 100644
--- a/include/grpc++/support/channel_arguments.h
+++ b/include/grpc++/support/channel_arguments.h
@@ -84,7 +84,7 @@
   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 2d4196b..e00e0d8 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 7a442e2..c8da593 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 @@
 /* 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 @@
    - 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 @@
    - 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 @@
    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 @@
 } 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 @@
 /* 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/security/client_auth_filter.c b/src/core/security/client_auth_filter.c
index c780b65..be2522a 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 @@
   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 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 2a8ffae..3db531c 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 @@
 
 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 @@
                                       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 @@
 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 @@
 
 /* -- 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 @@
   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 @@
     }
   }
   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 @@
   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 @@
   }
 }
 
-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 @@
       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 @@
           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 @@
   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 @@
   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 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 @@
   }
   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 @@
   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 @@
 
 /* -- 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 @@
   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 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 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 @@
 
 /* -- 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 @@
                    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 @@
 
 /* -- 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 @@
   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 @@
   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 @@
 
 /* -- 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 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 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 @@
 
 /* -- 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 @@
       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 @@
 
 /* -- 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 @@
   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 @@
     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 @@
   }
 
   /* 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 @@
 
 /* -- 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 @@
   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 @@
   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 @@
   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 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 c74beef..559574d 100644
--- a/src/core/security/credentials.h
+++ b/src/core/security/credentials.h
@@ -54,15 +54,17 @@
 
 #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_CHANNEL_CREDENTIALS_TYPE_SSL "Ssl"
+#define GRPC_CHANNEL_CREDENTIALS_TYPE_FAKE_TRANSPORT_SECURITY \
+  "FakeTransportSecurity"
 
-#define GRPC_AUTHORIZATION_METADATA_KEY "Authorization"
+#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 @@
 #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 *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 @@
                                              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 @@
 
 /* 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_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 @@
   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 @@
                                        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 @@
 /* -- 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 @@
 /* -- 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 4513530..e5a810f 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 @@
 }
 
 /* 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 @@
   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 @@
   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 @@
     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 @@
   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 7c4cf6f..8dbacdd 100644
--- a/src/core/security/security_connector.c
+++ b/src/core/security/security_connector.c
@@ -203,16 +203,6 @@
   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 @@
 
 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 @@
     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 @@
   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 @@
 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 @@
 }
 
 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 @@
     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 @@
   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 9218a3c..c5f00c5 100644
--- a/src/core/security/security_connector.h
+++ b/src/core/security/security_connector.h
@@ -145,7 +145,7 @@
 
 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 @@
 /* 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 @@
   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 ff3ad64..2068c97 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 @@
     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 @@
 
 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 2bbdc4b..794258e 100644
--- a/src/core/security/security_context.h
+++ b/src/core/security/security_context.h
@@ -85,7 +85,7 @@
    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/surface/secure_channel_create.c b/src/core/surface/secure_channel_create.c
index 1282ee9..0dd0a31 100644
--- a/src/core/surface/secure_channel_create.c
+++ b/src/core/surface/secure_channel_create.c
@@ -230,7 +230,7 @@
    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 @@
         "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 e559d51..962a721 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 8e582e5..f3d43fc 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 574656a..9bb358b 100644
--- a/src/cpp/client/client_context.cc
+++ b/src/cpp/client/client_context.cc
@@ -48,6 +48,7 @@
 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::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 @@
     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 @@
 }
 
 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 d2b2d30..3bbca80 100644
--- a/src/cpp/client/create_channel.cc
+++ b/src/cpp/client/create_channel.cc
@@ -44,12 +44,14 @@
 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 7a8149e..0c08db1 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 c476f3c..563fa92 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 @@
         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 8299ebe..a1b9a30 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 @@
                                  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 @@
     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 @@
   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 d354827..b241761 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 87d55cd..144b832 100644
--- a/src/csharp/Grpc.Core.Tests/FakeCredentials.cs
+++ b/src/csharp/Grpc.Core.Tests/FakeCredentials.cs
@@ -57,7 +57,7 @@
             get { return composable; }
         }
 
-        internal override CredentialsSafeHandle ToNativeCredentials()
+        internal override ChannelCredentialsSafeHandle ToNativeCredentials()
         {
             return null;
         }
@@ -65,7 +65,7 @@
 
     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 400a982..5ea179d 100644
--- a/src/csharp/Grpc.Core/CallCredentials.cs
+++ b/src/csharp/Grpc.Core/CallCredentials.cs
@@ -78,7 +78,7 @@
         /// 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 @@
             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 @@
             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 @@
             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 6b99055..f5eec96 100644
--- a/src/csharp/Grpc.Core/Channel.cs
+++ b/src/csharp/Grpc.Core/Channel.cs
@@ -75,8 +75,8 @@
             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 9d2bcda..5d96958 100644
--- a/src/csharp/Grpc.Core/ChannelCredentials.cs
+++ b/src/csharp/Grpc.Core/ChannelCredentials.cs
@@ -76,7 +76,7 @@
         /// 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 @@
 
         private sealed class InsecureCredentialsImpl : ChannelCredentials
         {
-            internal override CredentialsSafeHandle ToNativeCredentials()
+            internal override ChannelCredentialsSafeHandle ToNativeCredentials()
             {
                 return null;
             }
@@ -160,9 +160,9 @@
             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 @@
             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 0aab7bd..c4f7992 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 0000000..3678c7d
--- /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 ddeedeb..ad2e291 100644
--- a/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/CallSafeHandle.cs
@@ -100,7 +100,7 @@
             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 @@
             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 bab4510..8a58c64 100644
--- a/src/csharp/Grpc.Core/Internal/CredentialsSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ChannelCredentialsSafeHandle.cs
@@ -36,31 +36,31 @@
 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 @@
             }
         }
 
-        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 5f9169b..b3aa27c 100644
--- a/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
+++ b/src/csharp/Grpc.Core/Internal/ChannelSafeHandle.cs
@@ -45,7 +45,7 @@
         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 @@
             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 @@
             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 f76492c..2a571cd 100644
--- a/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
+++ b/src/csharp/Grpc.Core/Internal/NativeMetadataCredentialsPlugin.cs
@@ -46,7 +46,7 @@
         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 @@
         AsyncAuthInterceptor interceptor;
         GCHandle gcHandle;
         NativeMetadataInterceptor nativeInterceptor;
-        CredentialsSafeHandle credentials;
+        CallCredentialsSafeHandle credentials;
 
         public NativeMetadataCredentialsPlugin(AsyncAuthInterceptor interceptor)
         {
@@ -66,7 +66,7 @@
             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 8e582e5..f3d43fc 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 679ca43..1839319 100644
--- a/src/csharp/ext/grpc_csharp_ext.c
+++ b/src/csharp/ext/grpc_csharp_ext.c
@@ -785,9 +785,10 @@
                                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 @@
 
 /* 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 @@
   }
 }
 
-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 @@
   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 @@
   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 fe11905..a98ae85 100644
--- a/src/node/ext/call.cc
+++ b/src/node/ext/call.cc
@@ -757,7 +757,7 @@
   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 ff16a1f..9c5d9d2 100644
--- a/src/node/ext/call_credentials.cc
+++ b/src/node/ext/call_credentials.cc
@@ -64,11 +64,11 @@
 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 @@
   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 @@
   }
 }
 
-grpc_credentials *CallCredentials::GetWrappedCredentials() {
+grpc_call_credentials *CallCredentials::GetWrappedCredentials() {
   return wrapped_credentials;
 }
 
@@ -119,8 +119,8 @@
           "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 @@
   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 @@
   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 618292d..1cd8d8d 100644
--- a/src/node/ext/call_credentials.h
+++ b/src/node/ext/call_credentials.h
@@ -45,14 +45,14 @@
  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 @@
   // 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 c11734d..00fcca6 100644
--- a/src/node/ext/channel.cc
+++ b/src/node/ext/channel.cc
@@ -177,7 +177,7 @@
     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 7ca3b98..b77ff80 100644
--- a/src/node/ext/channel_credentials.cc
+++ b/src/node/ext/channel_credentials.cc
@@ -65,11 +65,11 @@
 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 @@
   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 @@
   }
 }
 
-grpc_credentials *ChannelCredentials::GetWrappedCredentials() {
+grpc_channel_credentials *ChannelCredentials::GetWrappedCredentials() {
   return wrapped_credentials;
 }
 
@@ -120,8 +121,8 @@
           "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 @@
     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 @@
   }
   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 31ea098..89b1152 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 @@
   // 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/test/credentials_test.js b/src/node/test/credentials_test.js
index 3e01b62..647f648 100644
--- a/src/node/test/credentials_test.js
+++ b/src/node/test/credentials_test.js
@@ -71,7 +71,7 @@
 var fakeFailingGoogleCredentials = {
   getRequestMetadata: function(service_url, callback) {
     setTimeout(function() {
-      callback(new Error('Authorization failure'));
+      callback(new Error('Authentication failure'));
     }, 0);
   }
 };
@@ -218,6 +218,25 @@
       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 @@
                             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 8e582e5..f3d43fc 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 4e0881e..b82b9fe 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 @@
 
 /** 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 ce16655..a573c17 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 @@
           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 @@
   });
 
   //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 @@
 }
 
 - (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/php/ext/grpc/call_credentials.c b/src/php/ext/grpc/call_credentials.c
new file mode 100644
index 0000000..17f167b
--- /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 86d7ae5..8f35ac6 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 a4313b6..f8c4f04 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 @@
 
 /**
  * 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 @@
     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/channel_credentials.c b/src/php/ext/grpc/channel_credentials.c
new file mode 100644
index 0000000..df4a5d5
--- /dev/null
+++ b/src/php/ext/grpc/channel_credentials.c
@@ -0,0 +1,187 @@
+/*
+ *
+ * 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_channel_credentials;
+
+/* 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_channel_credentials_release(creds->wrapped);
+  }
+  efree(creds);
+}
+
+/* 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_channel_credentials *intern;
+
+  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_channel_credentials, NULL TSRMLS_CC);
+  retval.handlers = zend_get_std_object_handlers();
+  return retval;
+}
+
+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_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 channel credentials object.
+ * @return ChannelCredentials The new default channel credentials object
+ */
+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);
+}
+
+/**
+ * Create SSL credentials.
+ * @param string pem_root_certs PEM encoding of the server root certificates
+ * @param string pem_private_key PEM encoding of the client's private key
+ *     (optional)
+ * @param string pem_cert_chain PEM encoding of the client's certificate chain
+ *     (optional)
+ * @return ChannelCredentials The new SSL credentials object
+ */
+PHP_METHOD(ChannelCredentials, createSsl) {
+  char *pem_root_certs = NULL;
+  grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
+
+  int root_certs_length = 0, private_key_length = 0, cert_chain_length = 0;
+
+  pem_key_cert_pair.private_key = pem_key_cert_pair.cert_chain = NULL;
+
+  /* "|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.cert_chain,
+                            &cert_chain_length) == FAILURE) {
+    zend_throw_exception(spl_ce_InvalidArgumentException,
+                         "createSsl expects 3 optional strings", 1 TSRMLS_CC);
+    return;
+  }
+  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_channel_credentials(creds);
+  RETURN_DESTROY_ZVAL(creds_object);
+}
+
+/**
+ * Create composite credentials from two existing credentials.
+ * @param ChannelCredentials cred1 The first credential
+ * @param CallCredentials cred2 The second credential
+ * @return ChannelCredentials The new composite credentials object
+ */
+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_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_channel_credentials *cred1 =
+      (wrapped_grpc_channel_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_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);
+}
+
+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_channel_credentials(TSRMLS_D) {
+  zend_class_entry ce;
+  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/credentials.h b/src/php/ext/grpc/channel_credentials.h
similarity index 75%
copy from src/php/ext/grpc/credentials.h
copy to src/php/ext/grpc/channel_credentials.h
index 86d7ae5..d89984c 100755
--- a/src/php/ext/grpc/credentials.h
+++ b/src/php/ext/grpc/channel_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_CHANNEL_CREDENTIALS_H_
+#define NET_GRPC_PHP_GRPC_CHANNEL_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 ChannelCredentials PHP class */
+extern zend_class_entry *grpc_ce_channel_credentials;
 
-/* Wrapper struct for grpc_credentials that can be associated with a PHP
- * object */
-typedef struct wrapped_grpc_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_credentials *wrapped;
-} wrapped_grpc_credentials;
+  grpc_channel_credentials *wrapped;
+} wrapped_grpc_channel_credentials;
 
-/* Initializes the Credentials PHP class */
-void grpc_init_credentials(TSRMLS_D);
+/* Initializes the ChannelCredentials PHP class */
+void grpc_init_channel_credentials(TSRMLS_D);
 
-#endif /* NET_GRPC_PHP_GRPC_CREDENTIALS_H_ */
+#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 8bacdfb..7928687 100755
--- a/src/php/ext/grpc/config.m4
+++ b/src/php/ext/grpc/config.m4
@@ -71,5 +71,7 @@
 
   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/credentials.c b/src/php/ext/grpc/credentials.c
deleted file mode 100644
index e413070..0000000
--- a/src/php/ext/grpc/credentials.c
+++ /dev/null
@@ -1,191 +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.
- *
- */
-
-#include "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_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;
-  if (creds->wrapped != NULL) {
-    grpc_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) {
-  zend_object_value retval;
-  wrapped_grpc_credentials *intern;
-
-  intern =
-      (wrapped_grpc_credentials *)emalloc(sizeof(wrapped_grpc_credentials));
-  memset(intern, 0, sizeof(wrapped_grpc_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);
-  retval.handlers = zend_get_std_object_handlers();
-  return retval;
-}
-
-zval *grpc_php_wrap_credentials(grpc_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(
-          credentials_object TSRMLS_CC);
-  credentials->wrapped = wrapped;
-  return credentials_object;
-}
-
-/**
- * Create a default credentials object.
- * @return Credentials The new default credentials object
- */
-PHP_METHOD(Credentials, createDefault) {
-  grpc_credentials *creds = grpc_google_default_credentials_create();
-  zval *creds_object = grpc_php_wrap_credentials(creds);
-  RETURN_DESTROY_ZVAL(creds_object);
-}
-
-/**
- * Create SSL credentials.
- * @param string pem_root_certs PEM encoding of the server root certificates
- * @param string pem_private_key PEM encoding of the client's private key
- *     (optional)
- * @param string pem_cert_chain PEM encoding of the client's certificate chain
- *     (optional)
- * @return Credentials The new SSL credentials object
- */
-PHP_METHOD(Credentials, createSsl) {
-  char *pem_root_certs = NULL;
-  grpc_ssl_pem_key_cert_pair pem_key_cert_pair;
-
-  int root_certs_length = 0, private_key_length = 0, cert_chain_length = 0;
-
-  pem_key_cert_pair.private_key = pem_key_cert_pair.cert_chain = NULL;
-
-  /* "|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.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(
-      pem_root_certs,
-      pem_key_cert_pair.private_key == NULL ? NULL : &pem_key_cert_pair, NULL);
-  zval *creds_object = grpc_php_wrap_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
- */
-PHP_METHOD(Credentials, 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) {
-    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(
-          cred1_obj TSRMLS_CC);
-  wrapped_grpc_credentials *cred2 =
-      (wrapped_grpc_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);
-  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};
-
-void grpc_init_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);
-}
diff --git a/src/php/ext/grpc/package.xml b/src/php/ext/grpc/package.xml
index 921cfc6..a2e3e28 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 @@
     <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 fcd94a6..762c013 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 @@
   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/tests/data/server1.pem b/src/php/tests/data/server1.pem
index 8e582e5..f3d43fc 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 3019866..9aab5c9 100755
--- a/src/php/tests/interop/interop_client.php
+++ b/src/php/tests/interop/interop_client.php
@@ -423,10 +423,10 @@
 
 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 e66bde3..c388ee5 100755
--- a/src/php/tests/unit_tests/SecureEndToEndTest.php
+++ b/src/php/tests/unit_tests/SecureEndToEndTest.php
@@ -35,7 +35,7 @@
 {
     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 8855c32..8dedf59 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 31fd470..9ab415d 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(
-    PyTypeObject *type, PyObject *ignored);
-ClientCredentials *pygrpc_ClientCredentials_jwt(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs);
-ClientCredentials *pygrpc_ClientCredentials_refresh_token(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs);
-ClientCredentials *pygrpc_ClientCredentials_iam(
-    PyTypeObject *type, PyObject *args, PyObject *kwargs);
-extern PyTypeObject pygrpc_ClientCredentials_type;
+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);
+CallCredentials *pygrpc_CallCredentials_jwt(
+    PyTypeObject *type, PyObject *args, PyObject *kwargs);
+CallCredentials *pygrpc_CallCredentials_refresh_token(
+    PyTypeObject *type, PyObject *args, PyObject *kwargs);
+CallCredentials *pygrpc_CallCredentials_iam(
+    PyTypeObject *type, PyObject *args, PyObject *kwargs);
+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 5604aba..04ec871 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_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 66%
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 90652b7..5a15a6e 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,
+PyMethodDef pygrpc_CallCredentials_methods[] = {
+    {"composite", (PyCFunction)pygrpc_CallCredentials_composite,
+     METH_CLASS|METH_KEYWORDS, ""},
+    {"compute_engine", (PyCFunction)pygrpc_CallCredentials_compute_engine,
      METH_CLASS|METH_NOARGS, ""},
-    {"ssl", (PyCFunction)pygrpc_ClientCredentials_ssl,
+    {"jwt", (PyCFunction)pygrpc_CallCredentials_jwt,
      METH_CLASS|METH_KEYWORDS, ""},
-    {"composite", (PyCFunction)pygrpc_ClientCredentials_composite,
+    {"refresh_token", (PyCFunction)pygrpc_CallCredentials_refresh_token,
      METH_CLASS|METH_KEYWORDS, ""},
-    {"compute_engine", (PyCFunction)pygrpc_ClientCredentials_compute_engine,
-     METH_CLASS|METH_NOARGS, ""},
-    {"jwt", (PyCFunction)pygrpc_ClientCredentials_jwt,
-     METH_CLASS|METH_KEYWORDS, ""},
-    {"refresh_token", (PyCFunction)pygrpc_ClientCredentials_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 @@
     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 @@
     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(
+CallCredentials *pygrpc_CallCredentials_composite(
     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(
-    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 @@
   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 @@
 }
 
 /* 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 @@
         &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 @@
   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 @@
   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 @@
         &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 79d39c4..c4db2a0 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 *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 0000000..83b1fc0
--- /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 e2feec6..5634c20 100644
--- a/src/python/grpcio/grpc/_adapter/_intermediary_low.py
+++ b/src/python/grpcio/grpc/_adapter/_intermediary_low.py
@@ -253,10 +253,10 @@
 
 
 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 70ceb2a..57146aa 100644
--- a/src/python/grpcio/grpc/_adapter/_low.py
+++ b/src/python/grpcio/grpc/_adapter/_low.py
@@ -33,7 +33,8 @@
 
 _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 5470d2d..ca0fa06 100644
--- a/src/python/grpcio/grpc/_adapter/_types.py
+++ b/src/python/grpcio/grpc/_adapter/_types.py
@@ -323,6 +323,14 @@
     """
     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 @@
     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 ed037b6..51c4668 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 @@
     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 b52ddb6..e25db3e 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/channel.pyx
@@ -37,7 +37,7 @@
 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 @@
       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 6b74a26..7a9fa7b 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 608207f..e9836fe 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 records
 
 
-cdef class ClientCredentials:
+cdef class ChannelCredentials:
 
   def __cinit__(self):
     self.c_credentials = NULL
@@ -47,7 +47,24 @@
 
   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 @@
       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 @@
     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 @@
     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 ClientCredentials credentials = ClientCredentials()
-  credentials.c_credentials = grpc.grpc_composite_credentials_create(
+  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 client_credentials_google_compute_engine():
-  cdef ClientCredentials credentials = ClientCredentials()
+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 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 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 @@
     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 @@
     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 62d40e7..36aea81 100644
--- a/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
+++ b/src/python/grpcio/grpc/_cython/_cygrpc/grpc.pxd
@@ -316,32 +316,40 @@
     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_credentials *grpc_composite_credentials_create(grpc_credentials *creds1,
-                                                      grpc_credentials *creds2,
-                                                      void *reserved)
-  grpc_credentials *grpc_google_compute_engine_credentials_create(
+  grpc_channel_credentials *grpc_composite_channel_credentials_create(
+      grpc_channel_credentials *creds1, grpc_call_credentials *creds2,
       void *reserved)
-  grpc_credentials *grpc_service_account_jwt_access_credentials_create(
+  void grpc_channel_credentials_release(grpc_channel_credentials *creds)
+
+  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_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 @@
                                         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 1ef2997..b20dda8 100644
--- a/src/python/grpcio/grpc/_cython/cygrpc.pyx
+++ b/src/python/grpcio/grpc/_cython/cygrpc.pyx
@@ -70,21 +70,24 @@
 
 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 07c8618..d4ca565 100644
--- a/src/python/grpcio/grpc/beta/interfaces.py
+++ b/src/python/grpcio/grpc/beta/interfaces.py
@@ -100,8 +100,11 @@
     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 bc9a434..3b40235 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 @@
     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 97fa4fe..ec68eb6 100644
--- a/src/python/grpcio/setup.py
+++ b/src/python/grpcio/setup.py
@@ -52,7 +52,8 @@
     '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 8e582e5..f3d43fc 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 fad57da..5916a9e 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 @@
     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 @@
     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 8e582e5..f3d43fc 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 a039d03..003e91a 100755
--- a/src/ruby/bin/apis/pubsub_demo.rb
+++ b/src/ruby/bin/apis/pubsub_demo.rb
@@ -66,7 +66,7 @@
 
 # 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 0ebd26f..d7e00e4 100755
--- a/src/ruby/bin/math_client.rb
+++ b/src/ruby/bin/math_client.rb
@@ -102,7 +102,7 @@
 
 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 390a9c5..3aa1187 100755
--- a/src/ruby/bin/noproto_client.rb
+++ b/src/ruby/bin/noproto_client.rb
@@ -68,7 +68,7 @@
 
 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_channel.c b/src/ruby/ext/grpc/rb_channel.c
index cd0b966..d5d8242 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
@@ -136,8 +136,8 @@
   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);
@@ -151,7 +151,7 @@
   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_credentials.c b/src/ruby/ext/grpc/rb_channel_credentials.c
new file mode 100644
index 0000000..072a6f5
--- /dev/null
+++ b/src/ruby/ext/grpc/rb_channel_credentials.c
@@ -0,0 +1,228 @@
+/*
+ *
+ * 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 "rb_channel_credentials.h"
+
+#include <ruby/ruby.h>
+
+#include <grpc/grpc.h>
+#include <grpc/grpc_security.h>
+
+#include "rb_grpc.h"
+
+/* grpc_rb_cChannelCredentials is the ruby class that proxies
+   grpc_channel_credentials. */
+static VALUE grpc_rb_cChannelCredentials = Qnil;
+
+/* 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_channel_credentials {
+  /* Holder of ruby objects involved in constructing the credentials */
+  VALUE mark;
+
+  /* The actual credentials */
+  grpc_channel_credentials *wrapped;
+} grpc_rb_channel_credentials;
+
+/* Destroys the credentials instances. */
+static void grpc_rb_channel_credentials_free(void *p) {
+  grpc_rb_channel_credentials *wrapper = NULL;
+  if (p == NULL) {
+    return;
+  };
+  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_channel_credentials_release(wrapper->wrapped);
+    wrapper->wrapped = NULL;
+  }
+
+  xfree(p);
+}
+
+/* Protects the mark object from GC */
+static void grpc_rb_channel_credentials_mark(void *p) {
+  grpc_rb_channel_credentials *wrapper = NULL;
+  if (p == NULL) {
+    return;
+  }
+  wrapper = (grpc_rb_channel_credentials *)p;
+
+  /* If it's not already cleaned up, mark the mark object */
+  if (wrapper->mark != Qnil) {
+    rb_gc_mark(wrapper->mark);
+  }
+}
+
+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,
+#ifdef RUBY_TYPED_FREE_IMMEDIATELY
+    RUBY_TYPED_FREE_IMMEDIATELY
+#endif
+};
+
+/* Allocates ChannelCredential instances.
+   Provides safe initial defaults for the instance fields. */
+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_channel_credentials_data_type, wrapper);
+}
+
+/* Clones ChannelCredentials instances.
+   Gives ChannelCredentials a consistent implementation of Ruby's object copy/dup
+   protocol. */
+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;
+  }
+
+  /* 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_channel_credentials_free) {
+    rb_raise(rb_eTypeError, "not a %s",
+             rb_obj_classname(grpc_rb_cChannelCredentials));
+  }
+
+  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_channel_credentials, 1);
+  return copy;
+}
+
+
+/* The attribute used on the mark object to hold the pem_root_certs. */
+static ID id_pem_root_certs;
+
+/* The attribute used on the mark object to hold the pem_private_key. */
+static ID id_pem_private_key;
+
+/* The attribute used on the mark object to hold the pem_private_key. */
+static ID id_pem_cert_chain;
+
+/*
+  call-seq:
+    creds1 = Credentials.new(pem_root_certs)
+    ...
+    creds2 = Credentials.new(pem_root_certs, pem_private_key,
+                             pem_cert_chain)
+    pem_root_certs: (required) PEM encoding of the server root certificate
+    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_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_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. */
+  /* "12" == 1 mandatory arg, 2 (credentials) is optional */
+  rb_scan_args(argc, argv, "12", &pem_root_certs, &pem_private_key,
+               &pem_cert_chain);
+
+  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");
+    return Qnil;
+  }
+  if (pem_private_key == Qnil && pem_cert_chain == Qnil) {
+    creds =
+        grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs), NULL, NULL);
+  } else {
+    key_cert_pair.private_key = RSTRING_PTR(pem_private_key);
+    key_cert_pair.cert_chain = RSTRING_PTR(pem_cert_chain);
+    creds = grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs),
+                                        &key_cert_pair, NULL);
+  }
+  if (creds == NULL) {
+    rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why");
+    return Qnil;
+  }
+  wrapper->wrapped = creds;
+
+  /* Add the input objects as hidden fields to preserve them. */
+  rb_ivar_set(self, id_pem_cert_chain, pem_cert_chain);
+  rb_ivar_set(self, id_pem_private_key, pem_private_key);
+  rb_ivar_set(self, id_pem_root_certs, pem_root_certs);
+
+  return self;
+}
+
+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_cChannelCredentials,
+                       grpc_rb_channel_credentials_alloc);
+
+  /* Provides a ruby constructor and support for dup/clone. */
+  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_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 840f7d5..15229de 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_credentials.c b/src/ruby/ext/grpc/rb_credentials.c
deleted file mode 100644
index 486ff79..0000000
--- a/src/ruby/ext/grpc/rb_credentials.c
+++ /dev/null
@@ -1,297 +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.
- *
- */
-
-#include "rb_credentials.h"
-
-#include <ruby/ruby.h>
-
-#include <grpc/grpc.h>
-#include <grpc/grpc_security.h>
-
-#include "rb_grpc.h"
-
-/* grpc_rb_cCredentials is the ruby class that proxies grpc_credentials. */
-static VALUE grpc_rb_cCredentials = Qnil;
-
-/* grpc_rb_credentials wraps a grpc_credentials.  It provides a
- * peer ruby object, 'mark' to minimize copying when a credential is
- * created from ruby. */
-typedef struct grpc_rb_credentials {
-  /* Holder of ruby objects involved in constructing the credentials */
-  VALUE mark;
-
-  /* The actual credentials */
-  grpc_credentials *wrapped;
-} grpc_rb_credentials;
-
-/* Destroys the credentials instances. */
-static void grpc_rb_credentials_free(void *p) {
-  grpc_rb_credentials *wrapper = NULL;
-  if (p == NULL) {
-    return;
-  };
-  wrapper = (grpc_rb_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);
-    wrapper->wrapped = NULL;
-  }
-
-  xfree(p);
-}
-
-/* Protects the mark object from GC */
-static void grpc_rb_credentials_mark(void *p) {
-  grpc_rb_credentials *wrapper = NULL;
-  if (p == NULL) {
-    return;
-  }
-  wrapper = (grpc_rb_credentials *)p;
-
-  /* If it's not already cleaned up, mark the mark object */
-  if (wrapper->mark != Qnil) {
-    rb_gc_mark(wrapper->mark);
-  }
-}
-
-static rb_data_type_t grpc_rb_credentials_data_type = {
-    "grpc_credentials",
-    {grpc_rb_credentials_mark, grpc_rb_credentials_free,
-     GRPC_RB_MEMSIZE_UNAVAILABLE, {NULL, NULL}},
-    NULL,
-    NULL,
-#ifdef RUBY_TYPED_FREE_IMMEDIATELY
-    RUBY_TYPED_FREE_IMMEDIATELY
-#endif
-};
-
-/* Allocates Credential 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);
-  wrapper->wrapped = NULL;
-  wrapper->mark = Qnil;
-  return TypedData_Wrap_Struct(cls, &grpc_rb_credentials_data_type, wrapper);
-}
-
-/* Clones Credentials instances.
-   Gives Credentials 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;
-
-  if (copy == orig) {
-    return copy;
-  }
-
-  /* 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));
-  }
-
-  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);
-
-  /* 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);
-  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;
-
-/* The attribute used on the mark object to hold the pem_private_key. */
-static ID id_pem_private_key;
-
-/* The attribute used on the mark object to hold the pem_private_key. */
-static ID id_pem_cert_chain;
-
-/*
-  call-seq:
-    creds1 = Credentials.new(pem_root_certs)
-    ...
-    creds2 = Credentials.new(pem_root_certs, pem_private_key,
-                             pem_cert_chain)
-    pem_root_certs: (required) PEM encoding of the server root certificate
-    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) {
-  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_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. */
-  /* "12" == 1 mandatory arg, 2 (credentials) is optional */
-  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);
-  if (pem_root_certs == Qnil) {
-    rb_raise(rb_eRuntimeError,
-             "could not create a credential: nil pem_root_certs");
-    return Qnil;
-  }
-  if (pem_private_key == Qnil && pem_cert_chain == Qnil) {
-    creds =
-        grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs), NULL, NULL);
-  } else {
-    key_cert_pair.private_key = RSTRING_PTR(pem_private_key);
-    key_cert_pair.cert_chain = RSTRING_PTR(pem_cert_chain);
-    creds = grpc_ssl_credentials_create(RSTRING_PTR(pem_root_certs),
-                                        &key_cert_pair, NULL);
-  }
-  if (creds == NULL) {
-    rb_raise(rb_eRuntimeError, "could not create a credentials, not sure why");
-    return Qnil;
-  }
-  wrapper->wrapped = creds;
-
-  /* Add the input objects as hidden fields to preserve them. */
-  rb_ivar_set(self, id_pem_cert_chain, pem_cert_chain);
-  rb_ivar_set(self, id_pem_private_key, pem_private_key);
-  rb_ivar_set(self, id_pem_root_certs, pem_root_certs);
-
-  return self;
-}
-
-void Init_grpc_credentials() {
-  grpc_rb_cCredentials =
-      rb_define_class_under(grpc_rb_mGrpcCore, "Credentials", rb_cObject);
-
-  /* Allocates an object managed by the ruby runtime */
-  rb_define_alloc_func(grpc_rb_cCredentials, grpc_rb_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);
-
-  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,
-                       wrapper);
-  return wrapper->wrapped;
-}
diff --git a/src/ruby/ext/grpc/rb_grpc.c b/src/ruby/ext/grpc/rb_grpc.c
index 33f4877..7c7c2d3 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;
@@ -318,7 +318,7 @@
   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/lib/grpc/generic/client_stub.rb b/src/ruby/lib/grpc/generic/client_stub.rb
index b8e33ad..90aaa02 100644
--- a/src/ruby/lib/grpc/generic/client_stub.rb
+++ b/src/ruby/lib/grpc/generic/client_stub.rb
@@ -51,7 +51,9 @@
       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 @@
     # @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/pb/test/client.rb b/src/ruby/pb/test/client.rb
index b84cd43..30550d6 100755
--- a/src/ruby/pb/test/client.rb
+++ b/src/ruby/pb/test/client.rb
@@ -103,13 +103,13 @@
 # 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/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 b02219d..b2bdf70 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 '#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 25cefcd..b4d2b94 100644
--- a/src/ruby/spec/channel_spec.rb
+++ b/src/ruby/spec/channel_spec.rb
@@ -40,7 +40,7 @@
   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 ad0fb26..734f176 100644
--- a/src/ruby/spec/client_server_spec.rb
+++ b/src/ruby/spec/client_server_spec.rb
@@ -431,7 +431,7 @@
     @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 c5173ae..da5bc6c 100644
--- a/src/ruby/spec/generic/client_stub_spec.rb
+++ b/src/ruby/spec/generic/client_stub_spec.rb
@@ -113,7 +113,7 @@
         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/testdata/server1.pem b/src/ruby/spec/testdata/server1.pem
index 8e582e5..f3d43fc 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 52070cf..be80750 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/end2end/data/server1_cert.c b/test/core/end2end/data/server1_cert.c
index d31f2e2..82d65cf 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 3e64cc0..bc009e1 100644
--- a/test/core/end2end/fixtures/h2_fakesec.c
+++ b/test/core/end2end/fixtures/h2_fakesec.c
@@ -73,14 +73,14 @@
   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 @@
 
 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 10db6c2..7a34cc6 100644
--- a/test/core/end2end/fixtures/h2_oauth2.c
+++ b/test/core/end2end/fixtures/h2_oauth2.c
@@ -118,14 +118,14 @@
   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 @@
 
 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 @@
       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 c2f41f4..37e1758 100644
--- a/test/core/end2end/fixtures/h2_ssl+poll.c
+++ b/test/core/end2end/fixtures/h2_ssl+poll.c
@@ -76,14 +76,14 @@
   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 @@
 
 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 896c60c..f5a006b 100644
--- a/test/core/end2end/fixtures/h2_ssl.c
+++ b/test/core/end2end/fixtures/h2_ssl.c
@@ -76,14 +76,14 @@
   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 @@
 
 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 413a8b8..7233cdb 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_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 @@
   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 @@
   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 @@
 
 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 4aeade1..bbfad21 100644
--- a/test/core/end2end/tests/call_creds.c
+++ b/test/core/end2end/tests/call_creds.c
@@ -132,27 +132,6 @@
   }
 }
 
-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 @@
   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 @@
     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 @@
       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 @@
   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 @@
   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 @@
 
 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 5c1e0f4..dcb35e5 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_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 @@
   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 @@
   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 @@
                                       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 @@
   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 @@
                                         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 @@
   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 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 @@
   /* 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 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 @@
   /* 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 @@
   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 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 @@
   /* 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 @@
   /* 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 @@
   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 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 @@
 
   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 @@
 
   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 @@
   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 764d8da..ee1178c 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 @@
 }
 
 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 @@
     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 f99d170..fcfe8a6 100644
--- a/test/core/security/oauth2_utils.c
+++ b/test/core/security/oauth2_utils.c
@@ -75,7 +75,8 @@
 
 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 @@
 
   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 8082351..b35fe79 100644
--- a/test/core/security/oauth2_utils.h
+++ b/test/core/security/oauth2_utils.h
@@ -42,7 +42,8 @@
 
 /* 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 f207e05..eb63724 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 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 @@
   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 @@
   }
   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 743ad06..418a544 100644
--- a/test/cpp/client/credentials_test.cc
+++ b/test/cpp/client/credentials_test.cc
@@ -46,8 +46,8 @@
 };
 
 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 cfb6c21..74290c3 100644
--- a/test/cpp/end2end/async_end2end_test.cc
+++ b/test/cpp/end2end/async_end2end_test.cc
@@ -199,7 +199,7 @@
 
   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, 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 058e696..116785b 100644
--- a/test/cpp/end2end/client_crash_test.cc
+++ b/test/cpp/end2end/client_crash_test.cc
@@ -74,7 +74,7 @@
     }));
     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 c5c7185..6da9333 100644
--- a/test/cpp/end2end/end2end_test.cc
+++ b/test/cpp/end2end/end2end_test.cc
@@ -146,13 +146,13 @@
 
   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 @@
     }
     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 @@
       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 @@
   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 @@
   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 @@
   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 @@
   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 @@
                                "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 6a46916..082119d 100644
--- a/test/cpp/end2end/generic_end2end_test.cc
+++ b/test/cpp/end2end/generic_end2end_test.cc
@@ -120,7 +120,7 @@
 
   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 80057d8..bd34cfb 100644
--- a/test/cpp/end2end/mock_test.cc
+++ b/test/cpp/end2end/mock_test.cc
@@ -244,7 +244,7 @@
 
   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 1786936..2baefcb 100644
--- a/test/cpp/end2end/server_crash_test_client.cc
+++ b/test/cpp/end2end/server_crash_test_client.cc
@@ -58,7 +58,7 @@
 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 0549bb8..b1b18b2 100644
--- a/test/cpp/end2end/shutdown_test.cc
+++ b/test/cpp/end2end/shutdown_test.cc
@@ -93,7 +93,7 @@
 
   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 d4ab148..b7e103a 100644
--- a/test/cpp/end2end/streaming_throughput_test.cc
+++ b/test/cpp/end2end/streaming_throughput_test.cc
@@ -160,7 +160,7 @@
 
   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 75a07d8..fb82b96 100644
--- a/test/cpp/end2end/thread_stress_test.cc
+++ b/test/cpp/end2end/thread_stress_test.cc
@@ -190,7 +190,7 @@
 
   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 d4c7f04..e88c0f9 100644
--- a/test/cpp/end2end/zookeeper_test.cc
+++ b/test/cpp/end2end/zookeeper_test.cc
@@ -157,7 +157,7 @@
 
   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 61b46d2..5caf0f2 100644
--- a/test/cpp/interop/client_helper.cc
+++ b/test/cpp/interop/client_helper.cc
@@ -76,11 +76,11 @@
 }
 
 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 @@
            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 @@
                              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 46a5255..6340007 100644
--- a/test/cpp/interop/interop_client.cc
+++ b/test/cpp/interop/interop_client.cc
@@ -244,7 +244,7 @@
 
   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 f8c55cf..3be2571 100644
--- a/test/cpp/interop/stress_interop_client.cc
+++ b/test/cpp/interop/stress_interop_client.cc
@@ -89,9 +89,9 @@
       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 5d14197..018f4ab 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 @@
 
 using std::make_pair;
 using std::pair;
-using std::thread;
 using std::vector;
 
 using grpc::testing::kTestCaseList;
@@ -202,7 +202,7 @@
 
   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 @@
         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 2c6247d..67bdcb2 100644
--- a/test/cpp/qps/driver.cc
+++ b/test/cpp/qps/driver.cc
@@ -162,7 +162,7 @@
   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 @@
   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 7877923..5caf3fe 100644
--- a/test/cpp/qps/report.h
+++ b/test/cpp/qps/report.h
@@ -115,8 +115,8 @@
         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 9c8d599..32cd8e4 100644
--- a/test/cpp/util/cli_call_test.cc
+++ b/test/cpp/util/cli_call_test.cc
@@ -89,7 +89,8 @@
   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 f0d5bfc..0cd9f9e 100644
--- a/test/cpp/util/create_test_channel.cc
+++ b/test/cpp/util/create_test_channel.cc
@@ -58,13 +58,14 @@
 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 @@
     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 @@
     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 a475068..b50d653 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(
     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 334b6ef..3f40b24 100644
--- a/test/cpp/util/grpc_cli.cc
+++ b/test/cpp/util/grpc_cli.cc
@@ -148,9 +148,9 @@
   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 0000000..c2d3da3
--- /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/doxygen/Doxyfile.c++ b/tools/doxygen/Doxyfile.c++
index 5d592c8..f077185 100644
--- a/tools/doxygen/Doxyfile.c++
+++ b/tools/doxygen/Doxyfile.c++
@@ -40,7 +40,7 @@
 # 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 bbd1706..11aaa37 100644
--- a/tools/doxygen/Doxyfile.c++.internal
+++ b/tools/doxygen/Doxyfile.c++.internal
@@ -40,7 +40,7 @@
 # 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 beb0128..e411abf 100644
--- a/tools/doxygen/Doxyfile.core
+++ b/tools/doxygen/Doxyfile.core
@@ -40,7 +40,7 @@
 # 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 4ce48b4..f0ec37b 100644
--- a/tools/doxygen/Doxyfile.core.internal
+++ b/tools/doxygen/Doxyfile.core.internal
@@ -40,7 +40,7 @@
 # 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