Implementing JWT credentials (a.k.a JWT ID Tokens).

- Not tested end to end yet
diff --git a/src/core/security/auth.c b/src/core/security/auth.c
index 58679a8..92878e3 100644
--- a/src/core/security/auth.c
+++ b/src/core/security/auth.c
@@ -48,6 +48,7 @@
 typedef struct {
   grpc_credentials *creds;
   grpc_mdstr *host;
+  grpc_mdstr *method;
   grpc_call_op op;
 } call_data;
 
@@ -56,6 +57,7 @@
   grpc_channel_security_context *security_context;
   grpc_mdctx *md_ctx;
   grpc_mdstr *authority_string;
+  grpc_mdstr *path_string;
   grpc_mdstr *error_msg_key;
 } channel_data;
 
@@ -89,6 +91,26 @@
   grpc_call_next_op(elem, &((call_data *)elem->call_data)->op);
 }
 
+static char *build_service_url(const char *url_scheme, call_data *calld) {
+  char *service_url;
+  char *service = gpr_strdup(grpc_mdstr_as_c_string(calld->method));
+  char *last_slash = strrchr(service, '/');
+  if (last_slash == NULL) {
+    gpr_log(GPR_ERROR, "No '/' found in fully qualified method name");
+    service[0] = '\0';
+  } else if (last_slash == service) {
+    /* No service part in fully qualified method name: will just be "/". */
+    service[1] = '\0';
+  } else {
+    *last_slash = '\0';
+  }
+  if (url_scheme == NULL) url_scheme = "";
+  gpr_asprintf(&service_url, "%s://%s%s", url_scheme,
+               grpc_mdstr_as_c_string(calld->host), service);
+  gpr_free(service);
+  return service_url;
+}
+
 static void send_security_metadata(grpc_call_element *elem, grpc_call_op *op) {
   /* grab pointers to our data from the call element */
   call_data *calld = elem->call_data;
@@ -106,9 +128,12 @@
   }
   if (channel_creds != NULL &&
       grpc_credentials_has_request_metadata(channel_creds)) {
+    char *service_url =
+        build_service_url(channeld->security_context->base.url_scheme, calld);
     calld->op = *op; /* Copy op (originates from the caller's stack). */
-    grpc_credentials_get_request_metadata(channel_creds,
+    grpc_credentials_get_request_metadata(channel_creds, service_url,
                                           on_credentials_metadata, elem);
+    gpr_free(service_url);
   } else {
     grpc_call_next_op(elem, op);
   }
@@ -146,6 +171,9 @@
       if (op->data.metadata->key == channeld->authority_string) {
         if (calld->host != NULL) grpc_mdstr_unref(calld->host);
         calld->host = grpc_mdstr_ref(op->data.metadata->value);
+      } else if (op->data.metadata->key == channeld->path_string) {
+        if (calld->method != NULL) grpc_mdstr_unref(calld->method);
+        calld->method = grpc_mdstr_ref(op->data.metadata->value);
       }
       grpc_call_next_op(elem, op);
       break;
@@ -194,6 +222,7 @@
   call_data *calld = elem->call_data;
   calld->creds = NULL;
   calld->host = NULL;
+  calld->method = NULL;
 }
 
 /* Destructor for call_data */
@@ -230,6 +259,7 @@
   channeld->md_ctx = metadata_context;
   channeld->authority_string =
       grpc_mdstr_from_string(channeld->md_ctx, ":authority");
+  channeld->path_string = grpc_mdstr_from_string(channeld->md_ctx, ":path");
   channeld->error_msg_key =
       grpc_mdstr_from_string(channeld->md_ctx, "grpc-message");
 }