diff --git a/services/identity/src/device_list.rs b/services/identity/src/device_list.rs
--- a/services/identity/src/device_list.rs
+++ b/services/identity/src/device_list.rs
@@ -205,6 +205,53 @@
   Ok(())
 }
 
+pub fn verify_initial_device_list(
+  device_list: &DeviceListUpdate,
+  expected_primary_device_id: &str,
+) -> Result<(), tonic::Status> {
+  use tonic::Status;
+  if device_list.last_primary_signature.is_some() {
+    debug!("Received lastPrimarySignature for initial device list");
+    return Err(Status::invalid_argument(
+      "invalid device list: unexpected lastPrimarySignature",
+    ));
+  }
+
+  let Some(signature) = &device_list.current_primary_signature else {
+    debug!("Missing curPrimarySignature for initial device list");
+    return Err(Status::invalid_argument(
+      "invalid device list: signature missing",
+    ));
+  };
+
+  crate::grpc_utils::ed25519_verify(
+    expected_primary_device_id,
+    &device_list.raw_payload,
+    signature,
+  )?;
+
+  if device_list.devices.len() != 1 {
+    debug!("Invalid device list length");
+    return Err(Status::invalid_argument(
+      "invalid device list: invalid length",
+    ));
+  }
+
+  if device_list
+    .devices
+    .first()
+    .filter(|it| **it == expected_primary_device_id)
+    .is_none()
+  {
+    debug!("Invalid primary device ID for initial device list");
+    return Err(Status::invalid_argument(
+      "invalid device list: invalid primary device",
+    ));
+  }
+
+  Ok(())
+}
+
 pub mod validation {
   use super::*;
   /// Returns `true` if `new_device_list` contains exactly one more new device