otpCode in plaintext. New integrations should use the current flow documented in Email auth & recovery and SMS authentication.
What changed
ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V7 is transitional: it accepts both
legacy verification tokens and the enclave-issued tokens returned by
VERIFY_OTP_V2. ACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V8 accepts only
enclave-issued tokens. During a staged rollout, legacy attempts must remain on
V7; updated attempts can use V7 or V8.INIT_OTP_V3returnsotpIdandotpEncryptionTargetBundle.- The client generates or selects a P-256 key pair.
- The client uses
encryptOtpCodeToBundleto encrypt the OTP code and public key withotpEncryptionTargetBundle. VERIFY_OTP_V2accepts the encrypted bundle and returns a verification token bound to the client public key.- The client signs the login or signup payload with the same private key.
OTP_LOGIN_V2or the sub-organization creation flow validates the verification token and client signature.
Upgrade the SDKs
The encrypted flow was introduced in the following releases. Use these versions or later, and upgrade related Turnkey packages together so their generated activity types and request shapes remain compatible.
Choose the section below that matches your integration.
- Wallet Kit and Core
- Legacy React SDK
- Server and low-level clients
In Pass the bundle to
@turnkey/react-wallet-kit, @turnkey/react-native-wallet-kit, and @turnkey/core, initOtp now returns an object instead of a plain OTP ID. Keep both values:verifyOtp. The SDK encrypts the OTP code and public key before calling Turnkey:verifyOtp no longer accepts contact or otpType, and it no longer returns subOrganizationId. Use completeOtp to perform verification plus account lookup and login/signup, or call proxyGetAccount separately after verification.loginWithOtp and signUpWithOtp no longer accept a separate publicKey. They reuse the key bound during verifyOtp and generate the required client signature automatically.Update policies before deploying
If a policy checks exact activity versions, update it before the new SDKs begin submitting activities. At minimum, review policies that name:ACTIVITY_TYPE_INIT_OTPorACTIVITY_TYPE_INIT_OTP_V2ACTIVITY_TYPE_VERIFY_OTPACTIVITY_TYPE_OTP_LOGINACTIVITY_TYPE_CREATE_SUB_ORGANIZATION_V7
activity.kind when the same policy should cover every version of a specific activity:
CREATE_SUB_ORGANIZATION covers every version of sub-organization creation,
not only OTP signup. Preserve any existing restrictions on who may create a
sub-organization and which parameters they may submit.Rollout checklist
- Update policies before deploying updated SDKs.
- Upgrade the frontend and backend Turnkey packages together.
- Store
otpId,otpEncryptionTargetBundle, and the client key as state for one OTP attempt. - On resend, replace all attempt state rather than reusing an old bundle or key.
- Test email and SMS separately if your application supports both.
- Test both an existing-user login and a new-user signup.
- Confirm that OTP codes are sent to your backend only as
encryptedOtpBundle. - After all clients have migrated, remove legacy activity versions from exact-version policies.