diff --git a/native/cpp/CommonCpp/NativeModules/CommRustModule.h b/native/cpp/CommonCpp/NativeModules/CommRustModule.h
--- a/native/cpp/CommonCpp/NativeModules/CommRustModule.h
+++ b/native/cpp/CommonCpp/NativeModules/CommRustModule.h
@@ -49,6 +49,12 @@
       jsi::Array contentOneTimeKeys,
       jsi::Array notifOneTimeKeys,
       jsi::String socialProof) override;
+  virtual jsi::Value updatePassword(
+      jsi::Runtime &rt,
+      jsi::String userID,
+      jsi::String deviceID,
+      jsi::String accessToken,
+      jsi::String password) override;
 
 public:
   CommRustModule(std::shared_ptr<facebook::react::CallInvoker> jsInvoker);
diff --git a/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp b/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp
--- a/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp
+++ b/native/cpp/CommonCpp/NativeModules/CommRustModule.cpp
@@ -173,4 +173,30 @@
       });
 }
 
+jsi::Value CommRustModule::updatePassword(
+    jsi::Runtime &rt,
+    jsi::String userID,
+    jsi::String deviceID,
+    jsi::String accessToken,
+    jsi::String password) {
+  return createPromiseAsJSIValue(
+      rt,
+      [this, &userID, &deviceID, &accessToken, &password](
+          jsi::Runtime &innerRt, std::shared_ptr<Promise> promise) {
+        std::string error;
+        try {
+          auto currentID = RustPromiseManager::instance.addPromise(
+              promise, this->jsInvoker_, innerRt);
+          identityUpdateUserPassword(
+              jsiStringToRustString(userID, innerRt),
+              jsiStringToRustString(deviceID, innerRt),
+              jsiStringToRustString(accessToken, innerRt),
+              jsiStringToRustString(password, innerRt),
+              currentID);
+        } catch (const std::exception &e) {
+          error = e.what();
+        };
+      });
+}
+
 } // namespace comm
diff --git a/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp b/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp
--- a/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp
+++ b/native/cpp/CommonCpp/_generated/rustJSI-generated.cpp
@@ -24,6 +24,9 @@
 static jsi::Value __hostFunction_CommRustModuleSchemaCxxSpecJSI_loginWalletUser(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
   return static_cast<CommRustModuleSchemaCxxSpecJSI *>(&turboModule)->loginWalletUser(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt), args[3].asString(rt), args[4].asString(rt), args[5].asString(rt), args[6].asString(rt), args[7].asString(rt), args[8].asObject(rt).asArray(rt), args[9].asObject(rt).asArray(rt), args[10].asString(rt));
 }
+static jsi::Value __hostFunction_CommRustModuleSchemaCxxSpecJSI_updatePassword(jsi::Runtime &rt, TurboModule &turboModule, const jsi::Value* args, size_t count) {
+  return static_cast<CommRustModuleSchemaCxxSpecJSI *>(&turboModule)->updatePassword(rt, args[0].asString(rt), args[1].asString(rt), args[2].asString(rt), args[3].asString(rt));
+}
 
 CommRustModuleSchemaCxxSpecJSI::CommRustModuleSchemaCxxSpecJSI(std::shared_ptr<CallInvoker> jsInvoker)
   : TurboModule("CommRustTurboModule", jsInvoker) {
@@ -31,6 +34,7 @@
   methodMap_["registerUser"] = MethodMetadata {10, __hostFunction_CommRustModuleSchemaCxxSpecJSI_registerUser};
   methodMap_["loginPasswordUser"] = MethodMetadata {10, __hostFunction_CommRustModuleSchemaCxxSpecJSI_loginPasswordUser};
   methodMap_["loginWalletUser"] = MethodMetadata {11, __hostFunction_CommRustModuleSchemaCxxSpecJSI_loginWalletUser};
+  methodMap_["updatePassword"] = MethodMetadata {4, __hostFunction_CommRustModuleSchemaCxxSpecJSI_updatePassword};
 }
 
 
diff --git a/native/cpp/CommonCpp/_generated/rustJSI.h b/native/cpp/CommonCpp/_generated/rustJSI.h
--- a/native/cpp/CommonCpp/_generated/rustJSI.h
+++ b/native/cpp/CommonCpp/_generated/rustJSI.h
@@ -24,6 +24,7 @@
   virtual jsi::Value registerUser(jsi::Runtime &rt, jsi::String username, jsi::String password, jsi::String keyPayload, jsi::String keyPayloadSignature, jsi::String contentPrekey, jsi::String contentPrekeySignature, jsi::String notifPrekey, jsi::String notifPrekeySignature, jsi::Array contentOneTimeKeys, jsi::Array notifOneTimeKeys) = 0;
   virtual jsi::Value loginPasswordUser(jsi::Runtime &rt, jsi::String username, jsi::String password, jsi::String keyPayload, jsi::String keyPayloadSignature, jsi::String contentPrekey, jsi::String contentPrekeySignature, jsi::String notifPrekey, jsi::String notifPrekeySignature, jsi::Array contentOneTimeKeys, jsi::Array notifOneTimeKeys) = 0;
   virtual jsi::Value loginWalletUser(jsi::Runtime &rt, jsi::String siweMessage, jsi::String siweSignature, jsi::String keyPayload, jsi::String keyPayloadSignature, jsi::String contentPrekey, jsi::String contentPrekeySignature, jsi::String notifPrekey, jsi::String notifPrekeySignature, jsi::Array contentOneTimeKeys, jsi::Array notifOneTimeKeys, jsi::String socialProof) = 0;
+  virtual jsi::Value updatePassword(jsi::Runtime &rt, jsi::String userID, jsi::String deviceID, jsi::String accessToken, jsi::String password) = 0;
 
 };
 
@@ -77,6 +78,14 @@
       return bridging::callFromJs<jsi::Value>(
           rt, &T::loginWalletUser, jsInvoker_, instance_, std::move(siweMessage), std::move(siweSignature), std::move(keyPayload), std::move(keyPayloadSignature), std::move(contentPrekey), std::move(contentPrekeySignature), std::move(notifPrekey), std::move(notifPrekeySignature), std::move(contentOneTimeKeys), std::move(notifOneTimeKeys), std::move(socialProof));
     }
+    jsi::Value updatePassword(jsi::Runtime &rt, jsi::String userID, jsi::String deviceID, jsi::String accessToken, jsi::String password) override {
+      static_assert(
+          bridging::getParameterCount(&T::updatePassword) == 5,
+          "Expected updatePassword(...) to have 5 parameters");
+
+      return bridging::callFromJs<jsi::Value>(
+          rt, &T::updatePassword, jsInvoker_, instance_, std::move(userID), std::move(deviceID), std::move(accessToken), std::move(password));
+    }
 
   private:
     T *instance_;
diff --git a/native/native_rust_library/src/lib.rs b/native/native_rust_library/src/lib.rs
--- a/native/native_rust_library/src/lib.rs
+++ b/native/native_rust_library/src/lib.rs
@@ -1,4 +1,4 @@
-use crate::ffi::string_callback;
+use crate::ffi::{string_callback, void_callback};
 use crate::identity::Empty;
 use comm_opaque2::client::{Login, Registration};
 use comm_opaque2::grpc::opaque_error_to_grpc_status as handle_error;
@@ -23,7 +23,8 @@
 use identity::{
   DeviceKeyUpload, DeviceType, IdentityKeyInfo, OpaqueLoginFinishRequest,
   OpaqueLoginStartRequest, PreKey, RegistrationFinishRequest,
-  RegistrationStartRequest, WalletLoginRequest,
+  RegistrationStartRequest, UpdateUserPasswordFinishRequest,
+  UpdateUserPasswordStartRequest, WalletLoginRequest,
 };
 
 #[cfg(not(feature = "android"))]
@@ -104,6 +105,15 @@
       promise_id: u32,
     );
 
+    #[cxx_name = "identityUpdateUserPassword"]
+    fn update_user_password(
+      user_id: String,
+      device_id: String,
+      access_token: String,
+      password: String,
+      promise_id: u32,
+    );
+
     #[cxx_name = "identityGenerateNonce"]
     fn generate_nonce(promise_id: u32);
 
@@ -119,6 +129,10 @@
     #[namespace = "comm"]
     #[cxx_name = "stringCallback"]
     fn string_callback(error: String, promise_id: u32, ret: String);
+
+    #[namespace = "comm"]
+    #[cxx_name = "voidCallback"]
+    fn void_callback(error: String, promise_id: u32);
   }
 }
 
@@ -134,6 +148,16 @@
   }
 }
 
+fn handle_void_result_as_callback<E>(result: Result<(), E>, promise_id: u32)
+where
+  E: std::fmt::Display,
+{
+  match result {
+    Err(e) => void_callback(e.to_string(), promise_id),
+    Ok(_) => void_callback("".to_string(), promise_id),
+  }
+}
+
 fn generate_nonce(promise_id: u32) {
   RUNTIME.spawn(async move {
     let result = fetch_nonce().await;
@@ -453,6 +477,70 @@
   Ok(serde_json::to_string(&user_id_and_access_token)?)
 }
 
+struct UpdatePasswordInfo {
+  user_id: String,
+  device_id: String,
+  access_token: String,
+  password: String,
+}
+
+fn update_user_password(
+  user_id: String,
+  device_id: String,
+  access_token: String,
+  password: String,
+  promise_id: u32,
+) {
+  RUNTIME.spawn(async move {
+    let update_password_info = UpdatePasswordInfo {
+      access_token,
+      user_id,
+      device_id,
+      password,
+    };
+    let result = update_user_password_helper(update_password_info).await;
+    handle_void_result_as_callback(result, promise_id);
+  });
+}
+
+async fn update_user_password_helper(
+  update_password_info: UpdatePasswordInfo,
+) -> Result<(), Error> {
+  let mut client_registration = Registration::new();
+  let opaque_registration_request = client_registration
+    .start(&update_password_info.password)
+    .map_err(handle_error)?;
+  let update_password_start_request = UpdateUserPasswordStartRequest {
+    opaque_registration_request,
+    access_token: update_password_info.access_token,
+    user_id: update_password_info.user_id,
+    device_id_key: update_password_info.device_id,
+  };
+  let mut identity_client =
+    IdentityClientServiceClient::connect("http://127.0.0.1:50054").await?;
+  let update_password_start_respone = identity_client
+    .update_user_password_start(update_password_start_request)
+    .await?
+    .into_inner();
+
+  let opaque_registration_upload = client_registration
+    .finish(
+      &update_password_info.password,
+      &update_password_start_respone.opaque_registration_response,
+    )
+    .map_err(handle_error)?;
+  let update_password_finish_request = UpdateUserPasswordFinishRequest {
+    session_id: update_password_start_respone.session_id,
+    opaque_registration_upload,
+  };
+
+  identity_client
+    .update_user_password_finish(update_password_finish_request)
+    .await?;
+
+  Ok(())
+}
+
 #[derive(
   Debug, derive_more::Display, derive_more::From, derive_more::Error,
 )]
diff --git a/native/schema/CommRustModuleSchema.js b/native/schema/CommRustModuleSchema.js
--- a/native/schema/CommRustModuleSchema.js
+++ b/native/schema/CommRustModuleSchema.js
@@ -44,6 +44,12 @@
     notifOneTimeKeys: $ReadOnlyArray<string>,
     socialProof: string,
   ) => Promise<string>;
+  +updatePassword: (
+    userID: string,
+    deviceID: string,
+    accessToken: string,
+    password: string,
+  ) => Promise<void>;
 }
 
 export default (TurboModuleRegistry.getEnforcing<Spec>(