Skip to main content

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). SMS pricing is usage-based and varies depending on the country of the destination phone number and the carrier. Prices are shown in U.S. cents per outbound SMS message segment. Taxes/surcharges separate. Select your country below to view pricing.
Select Your Country To View Pricing
Cost
0.000¢
Albania
Andorra
Angola
Argentina
Armenia
Australia
Austria
Azerbaijan
Bahamas
Bahrain
Bangladesh
Barbados
Belgium
Belize
Benin
Bermuda
Bolivia
Bosnia And Herzegovina
Botswana
Brazil
British Virgin Islands
Brunei
Bulgaria
Cameroon
Canada
Cape Verde
Cayman Islands
Chad
Chile
Colombia
Costa Rica
Croatia
Curacao
Cyprus
Czechia
Democratic Republic Of The Congo
Denmark
Djibouti
Dominica
Ecuador
El Salvador
England
Equatorial Guinea
Estonia
Faroe Islands
Fiji
Finland
France
French Polynesia
Gambia
Georgia
Germany
Ghana
Gibraltar
Greece
Greenland
Grenada
Guadelupe
Guatemala
Guinea
Guyana
Haiti
Honduras
Hong Kong
Hungary
Iceland
India
Indonesia
Ireland
Israel
Italy
Ivory Coast
Jamaica
Japan
Kosovo
Kuwait
Kyrgyzstan
Laos
Latvia
Lebanon
Lesotho
Liberia
Liechtenstein
Lithuania
Luxembourg
Madagascar
Malaysia
Maldives
Mali
Malta
Mauritius
Mexico
Moldova
Mongolia
Montenegro
Morocco
Mozambique
Namibia
Nepal
Netherlands
New Zealand
Nicaragua
Niger
Nigeria
Northern Ireland
Norway
Pakistan
Panama
Peru
Philippines
Poland
Portugal
Puerto Rico 1
Puerto Rico 2
Qatar
Reunion
Romania
Saint Lucia
Saint Vincent And Grenadines
Samoa
San Marino
Saudi Arabia
Scotland
Senegal
Serbia
Seychelles
Sierra Leone
Singapore
Slovakia
Slovenia
South Africa
South Korea
Spain
Suriname
Swaziland
Sweden
Switzerland
Tajikistan
Tanzania
Thailand
Togo
Trinidad And Tobago
Tunisia
Turkey
United Arab Emirates
United Kingdom
United States
Uruguay
Uzbekistan
Venezuela
Wales

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 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:
{
  "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 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:
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