Access and Pricing

SMS authentication is available to all Enterprise customers. To enable this feature, please reach out to the Turnkey team. 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 here as a CSV.

Prerequisites

Make sure you have set up your primary Turnkey organization with at least one API user that can programmatically initiate OTP and create suborganizations. 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)
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