diff --git a/src/node/ext/credentials.cc b/src/node/ext/credentials.cc
index 4f41c92f6a7926ddaf7a39f0c1ae8ef0adb68e7b..378031a4c1e58b45c34959188e905b21d50b51e5 100644
--- a/src/node/ext/credentials.cc
+++ b/src/node/ext/credentials.cc
@@ -242,5 +242,34 @@ NAN_METHOD(Credentials::CreateInsecure) {
   info.GetReturnValue().Set(WrapStruct(NULL));
 }
 
+NAN_METHOD(Credentials::CreateFromPlugin) {
+  if (!info[0]->IsFunction()) {
+    return Nan::ThrowTypeError(
+        "createFromPlugin's argument must be a function");
+  }
+  grpc_metadata_credentials_plugin plugin;
+  plugin_state *state = new plugin_state;
+  state->callback = new Nan::Callback(info[0].As<Function>());
+  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);
+  if (creds == NULL) {
+    info.GetReturnValue().SetNull();
+  } else {
+    info.GetReturnValue().Set(WrapStruct(creds()));
+  }
+}
+
+void plugin_get_metadata(void *state, const char *service_url,
+                         grpc_credentials_plugin_metadata_cb cb,
+                         void *user_data) {
+  uv_async_t *async = new uv_async_t;
+  uv_async_init(uv_default_loop(),
+                async,
+                PluginCallback);
+}
+
 }  // namespace node
 }  // namespace grpc
diff --git a/src/node/ext/credentials.h b/src/node/ext/credentials.h
index d6351a753e722bfee2cf9f9e6056c6f278b58841..553ef81c195a3a15ab4494a5c7fbfc016c268eca 100644
--- a/src/node/ext/credentials.h
+++ b/src/node/ext/credentials.h
@@ -83,13 +83,37 @@ typedef struct plugin_state {
   Nan::Callback *callback;
 } plugin_state;
 
+typedef struct plugin_callback_data {
+  plugin_state *state;
+  const char *service_url;
+  grpc_credentials_plugin_metadata_cb cb;
+  void *user_data;
+} plugin_callback_data;
+
 void plugin_get_metadata(void *state, const char *service_url,
-                         grpc_credentials_plugin_metadata_cb cb, void *user_data);
+                         grpc_credentials_plugin_metadata_cb cb,
+                         void *user_data);
 
 void plugin_destroy_state(void *state);
 
 static NAN_METHOD(PluginCallback);
 
+NAN_INLINE NAUV_WORK_CB(SendPluginCallback) {
+  Nan::HandleScope scope;
+  plugin_callback_data *data = reinterpret_cast<plugin_callback_data>(
+      async->data);
+  v8::Local<v8::Function> plugin_callback = Nan::GetFunction(
+      Nan::New<v8::FunctionTemplate>(PluginCallback).ToLocalChecked());
+  // Attach cb and user_data to plugin_callback so that it can access them later
+  const int argc = 2;
+  v8::Local<v8::Value> argv = {Nan::New(data->service_url).ToLocalChecked(),
+                               plugin_callback};
+  NanCallback *callback = static_cast<NanCallback*>(async->data);
+  callback->Call(argc, argv);
+  uv_unref((uv_handle_t *)async);
+  delete async;
+}
+
 }  // namespace node
 }  // namespace grpc