> ## Documentation Index
> Fetch the complete documentation index at: https://turnkey-0e7c1f5b-moeo-sync.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# SMS authentication

> SMS authentication enables users to authenticate their Turnkey account using their phone number via a 6-9 digit or bech32 alphanumeric one-time password (OTP). When authenticated, users receive an expiring API key stored in memory within an iframe, which functions like a session key to access their wallet.

## Access and pricing

SMS authentication is available to all Enterprise customers. To enable this feature, please reach out to the Turnkey team ([help@turnkey.com](mailto:help@turnkey.com)).

SMS pricing is usage-based and varies depending on the country of the destination phone number. A downloadable price list for all supported countries is available <a href="https://tkhq-prod-public-content.s3.us-east-1.amazonaws.com/sms-prices.csv" download>here as a CSV</a>.

## Prerequisites

Make sure you have set up your primary Turnkey organization with at least one API user that can programmatically initiate OTP and create sub-organizations. Check out our [Quickstart guide](/getting-started/quickstart) if you need help getting started. To allow an API user to initiate email auth, you'll need the following policy in your main organization:

```json
{
  "effect": "EFFECT_ALLOW",
  "consensus": "approvers.any(user, user.id == '<YOUR_API_USER_ID>')",
  "condition": "(activity.resource == 'AUTH' && activity.action == 'CREATE') || (activity.resource == 'OTP' && activity.action == 'CREATE') || (activity.resource == 'OTP' && activity.action == 'VERIFY') || (activity.resource == 'ORGANIZATION' && activity.action == 'CREATE')"
}
```

## How it works

SMS authentication uses three activities:

1. `INIT_OTP` - sends a 6-9 digit or bech32 alphanumeric OTP code to the specified phone number
2. `VERIFY_OTP` - verifies the code and returns a verificationToken JWT
3. `OTP_LOGIN` - verified the verificationToken and returns a session JWT

## Implementation

### Initiating SMS authentication

The flow begins with a new activity of type `ACTIVITY_TYPE_INIT_OTP` using the parent organization id with these parameters:

* `otpType`: specify `"OTP_TYPE_SMS"`
* `contact`: user's phone number
* `emailCustomization`: optional parameters for customizing emails
* `userIdentifier`: optional parameter for rate limiting SMS OTP requests per user.
  We recommend generating this server-side based on the user's IP address or public key.
  See the [OTP Rate Limits](#otp-rate-limits) section below for more details.
* `alphanumeric`: optional parameter for making this code bech32 alphanumeric or not. default: true
* `otpLength`: optional parameter for selecting the length of the OTP. default: 9
* `expirationSeconds`: optional validity window (defaults to 5 minutes)

#### One-Time Password Sandbox Environment

To test OTP codes in our sandbox environment you can use the following:

* `alphanumeric` must be set to `false`
* `otpLength` must be set to `6`
* Phone Numebr: +1 999-999-9999
* OTP Code: `000000`

After receiving the OTP, users complete OTP verification with `ACTIVITY_TYPE_VERIFY_OTP` using the parent organization id which returns a verificationToken JWT:

* `otpId`: ID from the init activity
* `otpCode`: the 6-9 digit or alphanumeric code received via email
* `expirationSeconds`: optional validity window (defaults to 1 hour)

After receiving the verification token, users complete OTP authentication flow with with `ACTIVITY_TYPE_OTP_LOGIN` using the sub orgazanition ID associated with the contact from the first step:

* `publicKey`: public key to add to organization data associated with the signing key in IndexedDB or SecureStorage.
* `verificationToken`: JWT returned from successfull `VERIFY_OTP` activity
* `expirationSeconds`: optional validity window (defaults to 15 minutes)
* `invalidateExisting`: optional boolean to invalidate previous login sessions

## Authorization

SMS authentication requires proper permissions through policies or parent organization status.

## Enabling/disabling SMS auth

### For top-level organizations

SMS authentication is disabled by default. Enable it using `ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE`:

```bash
turnkey request --host api.turnkey.com --path /public/v1/submit/set_organization_feature --body '{
        "timestampMs": "'"$(date +%s)"'000",
        "type": "ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE",
        "organizationId": "<YOUR-ORG-ID>",
        "parameters": {
                "name": "FEATURE_NAME_SMS_AUTH"
        }
}' --organization <YOUR-ORG-ID>
```

### For sub-organizations

* SMS auth is enabled by default
* Disable during creation using `disableSmsAuth: true` in the `CreateSubOrganizationIntentV7` activity
* Disable after creation using `ACTIVITY_TYPE_REMOVE_ORGANIZATION_FEATURE` with feature name `FEATURE_NAME_SMS_AUTH`

## Implementation notes

* Users are limited to 10 long-lived API keys and 10 expiring API keys
* When the expiring API key limit is reached, the oldest key is automatically discarded

## OTP rate limits

In order to safeguard users, Turnkey enforces rate limits for OTP auth activities. If a `userIdentifier` parameter is provided, the following limits are enforced:

* 3 requests per 3 minutes per unique `userIdentifier`
* 3 retries max per code, after which point that code will be locked
* 3 active codes per user, each with a 5 minute TTL
