diff --git a/services/tunnelbroker/src/grpc/mod.rs b/services/tunnelbroker/src/grpc/mod.rs
--- a/services/tunnelbroker/src/grpc/mod.rs
+++ b/services/tunnelbroker/src/grpc/mod.rs
@@ -71,6 +71,24 @@
     let response = tonic::Response::new(Empty {});
     Ok(response)
   }
+
+  async fn delete_device_data(
+    &self,
+    request: tonic::Request<proto::DeleteDeviceDataRequest>,
+  ) -> Result<tonic::Response<proto::Empty>, tonic::Status> {
+    let message = request.into_inner();
+
+    debug!("Deleting {} data", &message.device_id);
+
+    self
+      .client
+      .remove_device_token(&message.device_id)
+      .await
+      .map_err(|_| tonic::Status::failed_precondition("unexpected error"))?;
+
+    let response = tonic::Response::new(Empty {});
+    Ok(response)
+  }
 }
 
 pub async fn run_server(
diff --git a/shared/protos/tunnelbroker.proto b/shared/protos/tunnelbroker.proto
--- a/shared/protos/tunnelbroker.proto
+++ b/shared/protos/tunnelbroker.proto
@@ -13,6 +13,9 @@
   // Tunnelbroker will enqueue the message, and send it next time the device
   // connects to tunnelbroker and flushes the queue.
   rpc SendMessageToDevice(MessageToDevice) returns (Empty) {}
+
+  // Deleting data associated with device.
+  rpc DeleteDeviceData(DeleteDeviceDataRequest) returns (Empty) {}
 }
 
 message Empty {}
@@ -23,3 +26,8 @@
   // JSON encoded message. See shared/tunnelbroker_messages for valid payloads
   string payload = 2;
 }
+
+message DeleteDeviceDataRequest {
+  // The primary identity key of a device
+  string device_id = 1;
+}