diff --git a/include/grpc++/credentials.h b/include/grpc++/credentials.h
index c677cc3e0a3edd8bc01f3d0805ece638e5213760..59ad638f47dbd0c3341f7046cb687f57a8d6cc2c 100644
--- a/include/grpc++/credentials.h
+++ b/include/grpc++/credentials.h
@@ -105,6 +105,14 @@ std::unique_ptr<Credentials> ServiceAccountCredentials(
     const grpc::string& json_key, const grpc::string& scope,
     std::chrono::seconds token_lifetime);
 
+// Builds JWT credentials.
+// json_key is the JSON key string containing the client's private key.
+// 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.
+std::unique_ptr<Credentials> JWTCredentials(
+    const grpc::string& json_key, std::chrono::seconds token_lifetime);
+
 // Builds IAM credentials.
 std::unique_ptr<Credentials> IAMCredentials(
     const grpc::string& authorization_token,
diff --git a/src/cpp/client/secure_credentials.cc b/src/cpp/client/secure_credentials.cc
index 6ca702eeadbd1e27996500cf671711b68ee24cd5..a2f6a698583e9c746130eb35ca78e1a08ac150f3 100644
--- a/src/cpp/client/secure_credentials.cc
+++ b/src/cpp/client/secure_credentials.cc
@@ -98,12 +98,30 @@ std::unique_ptr<Credentials> ComputeEngineCredentials() {
 std::unique_ptr<Credentials> ServiceAccountCredentials(
     const grpc::string& json_key, const grpc::string& scope,
     std::chrono::seconds token_lifetime) {
-  gpr_timespec lifetime = gpr_time_from_seconds(
-      token_lifetime.count() > 0 ? token_lifetime.count() : 0);
+  if (token_lifetime.count() <= 0) {
+    gpr_log(GPR_ERROR,
+            "Trying to create ServiceAccountCredentials "
+            "with non-positive lifetime");
+    return WrapCredentials(nullptr);
+  }
+  gpr_timespec lifetime = gpr_time_from_seconds(token_lifetime.count());
   return WrapCredentials(grpc_service_account_credentials_create(
       json_key.c_str(), scope.c_str(), lifetime));
 }
 
+// Builds JWT credentials.
+std::unique_ptr<Credentials> JWTCredentials(
+    const grpc::string &json_key, std::chrono::seconds token_lifetime) {
+  if (token_lifetime.count() <= 0) {
+    gpr_log(GPR_ERROR,
+            "Trying to create JWTCredentials with non-positive lifetime");
+    return WrapCredentials(nullptr);
+  }
+  gpr_timespec lifetime = gpr_time_from_seconds(token_lifetime.count());
+  return WrapCredentials(
+      grpc_jwt_credentials_create(json_key.c_str(), lifetime));
+}
+
 // Builds IAM credentials.
 std::unique_ptr<Credentials> IAMCredentials(
     const grpc::string& authorization_token,
diff --git a/test/cpp/interop/client.cc b/test/cpp/interop/client.cc
index ae68f7a55649b79be08f46123f690c0058a98c8e..e5645e568e0871ef3766409c7d716caef5107c8e 100644
--- a/test/cpp/interop/client.cc
+++ b/test/cpp/interop/client.cc
@@ -73,6 +73,7 @@ DEFINE_string(test_case, "large_unary",
               "ping_pong : full-duplex streaming; "
               "service_account_creds : large_unary with service_account auth; "
               "compute_engine_creds: large_unary with compute engine auth; "
+              "jwt_token_creds: large_unary with JWT token auth; "
               "all : all of above.");
 DEFINE_string(default_service_account, "",
               "Email of GCE default service account");
@@ -85,6 +86,7 @@ using grpc::ClientContext;
 using grpc::ComputeEngineCredentials;
 using grpc::CreateTestChannel;
 using grpc::Credentials;
+using grpc::JWTCredentials;
 using grpc::ServiceAccountCredentials;
 using grpc::testing::ResponseParameters;
 using grpc::testing::SimpleRequest;
@@ -146,6 +148,13 @@ std::shared_ptr<ChannelInterface> CreateChannelForTestCase(
     creds = ComputeEngineCredentials();
     return CreateTestChannel(host_port, FLAGS_server_host_override,
                              FLAGS_enable_ssl, FLAGS_use_prod_roots, creds);
+  } else if (test_case == "jwt_token_creds") {
+    std::unique_ptr<Credentials> creds;
+    GPR_ASSERT(FLAGS_enable_ssl);
+    grpc::string json_key = GetServiceAccountJsonKey();
+    creds = JWTCredentials(json_key, std::chrono::hours(1));
+    return CreateTestChannel(host_port, FLAGS_server_host_override,
+                             FLAGS_enable_ssl, FLAGS_use_prod_roots, creds);
   } else {
     return CreateTestChannel(host_port, FLAGS_server_host_override,
                              FLAGS_enable_ssl, FLAGS_use_prod_roots);
@@ -227,6 +236,21 @@ void DoServiceAccountCreds() {
   gpr_log(GPR_INFO, "Large unary with service account creds done.");
 }
 
+void DoJwtTokenCreds() {
+  gpr_log(GPR_INFO,
+          "Sending a large unary rpc with JWT token credentials ...");
+  std::shared_ptr<ChannelInterface> channel =
+      CreateChannelForTestCase("jwt_token_creds");
+  SimpleRequest request;
+  SimpleResponse response;
+  request.set_fill_username(true);
+  PerformLargeUnary(channel, &request, &response);
+  GPR_ASSERT(!response.username().empty());
+  grpc::string json_key = GetServiceAccountJsonKey();
+  GPR_ASSERT(json_key.find(response.username()) != grpc::string::npos);
+  gpr_log(GPR_INFO, "Large unary with JWT token creds done.");
+}
+
 void DoLargeUnary() {
   gpr_log(GPR_INFO, "Sending a large unary rpc...");
   std::shared_ptr<ChannelInterface> channel =
@@ -415,6 +439,8 @@ int main(int argc, char** argv) {
     DoServiceAccountCreds();
   } else if (FLAGS_test_case == "compute_engine_creds") {
     DoComputeEngineCreds();
+  } else if (FLAGS_test_case == "jwt_token_creds") {
+    DoJwtTokenCreds();
   } else if (FLAGS_test_case == "all") {
     DoEmpty();
     DoLargeUnary();
@@ -422,9 +448,10 @@ int main(int argc, char** argv) {
     DoResponseStreaming();
     DoHalfDuplex();
     DoPingPong();
-    // service_account_creds can only run with ssl.
+    // service_account_creds and jwt_token_creds can only run with ssl.
     if (FLAGS_enable_ssl) {
       DoServiceAccountCreds();
+      DoJwtTokenCreds();
     }
     // compute_engine_creds only runs in GCE.
   } else {
@@ -432,7 +459,7 @@ int main(int argc, char** argv) {
         GPR_ERROR,
         "Unsupported test case %s. Valid options are all|empty_unary|"
         "large_unary|client_streaming|server_streaming|half_duplex|ping_pong|"
-        "service_account_creds|compute_engine_creds",
+        "service_account_creds|compute_engine_creds|jwt_token_creds",
         FLAGS_test_case.c_str());
   }