diff --git a/lib/types/identity-service-types.js b/lib/types/identity-service-types.js
--- a/lib/types/identity-service-types.js
+++ b/lib/types/identity-service-types.js
@@ -53,3 +53,5 @@
   +accessToken: string,
   +username: string,
 };
+
+export const ONE_TIME_KEYS_NUMBER = 10;
diff --git a/lib/types/redux-types.js b/lib/types/redux-types.js
--- a/lib/types/redux-types.js
+++ b/lib/types/redux-types.js
@@ -44,6 +44,7 @@
   CalendarThreadFilter,
   SetCalendarDeletedFilterPayload,
 } from './filter-types.js';
+import type { IdentityRegisterResult } from './identity-service-types.js';
 import type { IntegrityStore } from './integrity-types.js';
 import type {
   KeyserverStore,
@@ -374,6 +375,21 @@
       +payload: RegisterResult,
       +loadingInfo: LoadingInfo,
     }
+  | {
+      +type: 'IDENTITY_REGISTER_STARTED',
+      +payload?: void,
+      +loadingInfo: LoadingInfo,
+    }
+  | {
+      +type: 'IDENTITY_REGISTER_FAILED',
+      +payload: Error,
+      +loadingInfo: LoadingInfo,
+    }
+  | {
+      +type: 'IDENTITY_REGISTER_SUCCESS',
+      +payload: IdentityRegisterResult,
+      +loadingInfo: LoadingInfo,
+    }
   | {
       +type: 'CHANGE_KEYSERVER_USER_PASSWORD_STARTED',
       +payload?: void,
diff --git a/native/account/register-panel.react.js b/native/account/register-panel.react.js
--- a/native/account/register-panel.react.js
+++ b/native/account/register-panel.react.js
@@ -46,7 +46,11 @@
 import { useSelector } from '../redux/redux-utils.js';
 import { nativeLogInExtraInfoSelector } from '../selectors/account-selectors.js';
 import type { KeyPressEvent } from '../types/react-native.js';
-import { AppOutOfDateAlertDetails } from '../utils/alert-messages.js';
+import {
+  AppOutOfDateAlertDetails,
+  UsernameReservedAlertDetails,
+  UsernameTakenAlertDetails,
+} from '../utils/alert-messages.js';
 import Alert from '../utils/alert.js';
 import { nativeNotificationsSessionCreator } from '../utils/crypto-utils.js';
 import { type StateContainer } from '../utils/state-container.js';
@@ -365,16 +369,15 @@
     } catch (e) {
       if (e.message === 'username_reserved') {
         Alert.alert(
-          'Username reserved',
-          'This username is currently reserved. Please contact support@' +
-            'comm.app if you would like to claim this account.',
+          UsernameReservedAlertDetails.title,
+          UsernameReservedAlertDetails.message,
           [{ text: 'OK', onPress: this.onUsernameAlertAcknowledged }],
           { cancelable: false },
         );
       } else if (e.message === 'username_taken') {
         Alert.alert(
-          'Username taken',
-          'An account with that username already exists',
+          UsernameTakenAlertDetails.title,
+          UsernameTakenAlertDetails.message,
           [{ text: 'OK', onPress: this.onUsernameAlertAcknowledged }],
           { cancelable: false },
         );
diff --git a/native/account/registration/registration-server-call.js b/native/account/registration/registration-server-call.js
--- a/native/account/registration/registration-server-call.js
+++ b/native/account/registration/registration-server-call.js
@@ -6,11 +6,14 @@
 import {
   keyserverRegisterActionTypes,
   keyserverRegister,
+  useIdentityRegister,
+  identityRegisterActionTypes,
 } from 'lib/actions/user-actions.js';
 import type { LogInStartingPayload } from 'lib/types/account-types.js';
 import { useServerCall } from 'lib/utils/action-utils.js';
 import { useDispatchActionPromise } from 'lib/utils/redux-promise-utils.js';
 import { useDispatch } from 'lib/utils/redux-utils.js';
+import { usingCommServicesAccessToken } from 'lib/utils/services-utils.js';
 import { setURLPrefix } from 'lib/utils/url-utils.js';
 
 import type {
@@ -24,7 +27,11 @@
 } from '../../avatars/avatar-hooks.js';
 import { useSelector } from '../../redux/redux-utils.js';
 import { nativeLogInExtraInfoSelector } from '../../selectors/account-selectors.js';
-import { AppOutOfDateAlertDetails } from '../../utils/alert-messages.js';
+import {
+  AppOutOfDateAlertDetails,
+  UsernameReservedAlertDetails,
+  UsernameTakenAlertDetails,
+} from '../../utils/alert-messages.js';
 import Alert from '../../utils/alert.js';
 import { setNativeCredentials } from '../native-credentials.js';
 import { useSIWEServerCall } from '../siwe-hooks.js';
@@ -59,17 +66,62 @@
   const logInExtraInfo = useSelector(nativeLogInExtraInfoSelector);
 
   const dispatchActionPromise = useDispatchActionPromise();
-  const callRegister = useServerCall(keyserverRegister);
+  const callKeyserverRegister = useServerCall(keyserverRegister);
+  const callIdentityRegister = useIdentityRegister();
+
+  const identityRegisterUsernameAccount = React.useCallback(
+    async (accountSelection: UsernameAccountSelection) => {
+      const identityRegisterPromise = (async () => {
+        try {
+          const result = await callIdentityRegister(
+            accountSelection.username,
+            accountSelection.password,
+          );
+          await setNativeCredentials({
+            username: accountSelection.username,
+            password: accountSelection.password,
+          });
+          return result;
+        } catch (e) {
+          if (e.message === 'username reserved') {
+            Alert.alert(
+              UsernameReservedAlertDetails.title,
+              UsernameReservedAlertDetails.message,
+            );
+          } else if (e.message === 'username already exists') {
+            Alert.alert(
+              UsernameTakenAlertDetails.title,
+              UsernameTakenAlertDetails.message,
+            );
+          } else if (e.message === 'Unsupported version') {
+            Alert.alert(
+              AppOutOfDateAlertDetails.title,
+              AppOutOfDateAlertDetails.message,
+            );
+          } else {
+            Alert.alert('Unknown error', 'Uhh... try again?');
+          }
+          throw e;
+        }
+      })();
+      void dispatchActionPromise(
+        identityRegisterActionTypes,
+        identityRegisterPromise,
+      );
+      await identityRegisterPromise;
+    },
+    [callIdentityRegister, dispatchActionPromise],
+  );
 
-  const registerUsernameAccount = React.useCallback(
+  const keyserverRegisterUsernameAccount = React.useCallback(
     async (
       accountSelection: UsernameAccountSelection,
       keyserverURL: string,
     ) => {
       const extraInfo = await logInExtraInfo();
-      const registerPromise = (async () => {
+      const keyserverRegisterPromise = (async () => {
         try {
-          const result = await callRegister(
+          const result = await callKeyserverRegister(
             {
               ...extraInfo,
               username: accountSelection.username,
@@ -87,14 +139,13 @@
         } catch (e) {
           if (e.message === 'username_reserved') {
             Alert.alert(
-              'Username reserved',
-              'This username is currently reserved. Please contact support@' +
-                'comm.app if you would like to claim this account.',
+              UsernameReservedAlertDetails.title,
+              UsernameReservedAlertDetails.message,
             );
           } else if (e.message === 'username_taken') {
             Alert.alert(
-              'Username taken',
-              'An account with that username already exists',
+              UsernameTakenAlertDetails.title,
+              UsernameTakenAlertDetails.message,
             );
           } else if (e.message === 'client_version_unsupported') {
             Alert.alert(
@@ -109,13 +160,13 @@
       })();
       void dispatchActionPromise(
         keyserverRegisterActionTypes,
-        registerPromise,
+        keyserverRegisterPromise,
         undefined,
         ({ calendarQuery: extraInfo.calendarQuery }: LogInStartingPayload),
       );
-      await registerPromise;
+      await keyserverRegisterPromise;
     },
-    [logInExtraInfo, callRegister, dispatchActionPromise],
+    [logInExtraInfo, callKeyserverRegister, dispatchActionPromise],
   );
 
   const siweServerCall = useSIWEServerCall();
@@ -130,8 +181,16 @@
               return;
             }
             const { accountSelection, avatarData, keyserverURL } = input;
-            if (accountSelection.accountType === 'username') {
-              await registerUsernameAccount(accountSelection, keyserverURL);
+            if (
+              accountSelection.accountType === 'username' &&
+              !usingCommServicesAccessToken
+            ) {
+              await keyserverRegisterUsernameAccount(
+                accountSelection,
+                keyserverURL,
+              );
+            } else if (accountSelection.accountType === 'username') {
+              await identityRegisterUsernameAccount(accountSelection);
             } else {
               try {
                 await siweServerCall(accountSelection, {
@@ -157,7 +216,13 @@
           }
         },
       ),
-    [currentStep, registerUsernameAccount, siweServerCall, dispatch],
+    [
+      currentStep,
+      keyserverRegisterUsernameAccount,
+      identityRegisterUsernameAccount,
+      siweServerCall,
+      dispatch,
+    ],
   );
 
   // STEP 2: SETTING AVATAR
diff --git a/native/identity-service/identity-service-context-provider.react.js b/native/identity-service/identity-service-context-provider.react.js
--- a/native/identity-service/identity-service-context-provider.react.js
+++ b/native/identity-service/identity-service-context-provider.react.js
@@ -2,12 +2,14 @@
 
 import * as React from 'react';
 
+import { getOneTimeKeyArray } from 'lib/shared/crypto-utils.js';
 import { IdentityClientContext } from 'lib/shared/identity-client-context.js';
 import type {
   IdentityServiceClient,
   OutboundKeyInfoResponse,
   UserLoginResponse,
 } from 'lib/types/identity-service-types.js';
+import { ONE_TIME_KEYS_NUMBER } from 'lib/types/identity-service-types.js';
 
 import { getCommServicesAuthMetadataEmitter } from '../event-emitters/csa-auth-metadata-emitter.js';
 import { commCoreModule, commRustModule } from '../native-modules.js';
@@ -87,6 +89,34 @@
         }
         return resultObject;
       },
+      registerUser: async (username: string, password: string) => {
+        await commCoreModule.initializeCryptoAccount();
+        const [
+          { blobPayload, signature },
+          notificationsOneTimeKeys,
+          primaryOneTimeKeys,
+          prekeys,
+        ] = await Promise.all([
+          commCoreModule.getUserPublicKey(),
+          commCoreModule.getNotificationsOneTimeKeys(ONE_TIME_KEYS_NUMBER),
+          commCoreModule.getPrimaryOneTimeKeys(ONE_TIME_KEYS_NUMBER),
+          commCoreModule.generateAndGetPrekeys(),
+        ]);
+        const registrationResult = await commRustModule.registerUser(
+          username,
+          password,
+          blobPayload,
+          signature,
+          prekeys.contentPrekey,
+          prekeys.contentPrekeySignature,
+          prekeys.notifPrekey,
+          prekeys.notifPrekeySignature,
+          getOneTimeKeyArray(primaryOneTimeKeys),
+          getOneTimeKeyArray(notificationsOneTimeKeys),
+        );
+        const { userID, accessToken } = JSON.parse(registrationResult);
+        return { accessToken, userID, username };
+      },
     };
   }, [getAuthMetadata]);
 
diff --git a/native/utils/alert-messages.js b/native/utils/alert-messages.js
--- a/native/utils/alert-messages.js
+++ b/native/utils/alert-messages.js
@@ -18,3 +18,15 @@
     'Your app version is pretty old, and the server doesn’t know how ' +
     `to speak to it anymore. Please use the ${platformStore} to update!`,
 };
+
+export const UsernameReservedAlertDetails: AlertDetails = {
+  title: 'Username reserved',
+  message:
+    'This username is currently reserved. Please contact support@' +
+    'comm.app if you would like to claim this account.',
+};
+
+export const UsernameTakenAlertDetails: AlertDetails = {
+  title: 'Username taken',
+  message: 'An account with that username already exists',
+};