Overview
Email Authentication enables users to authenticate and recover their Turnkey accounts using email-based verification. There are two methods of email authentication:
One-Time Password
- Uses a 6-digit one-time password sent via email
- Simple, and familiar user experience
Credential Bundle
- Sends an encrypted API key credential directly via email
- Alternative method for specific use cases
- More secure, but requires copying the full credential to the client
Both methods provide users with an expiring API key for authentication or account recovery.
Core Mechanism
Email Authentication is built with expiring API keys as the foundation. The two delivery mechanisms are:
OTP-based Method
The authentication process happens in two steps:
- A 6-digit OTP code is sent to the user's verified email address
- Upon verification of the correct code, an API key credential is generated and encrypted for the client
Credential Bundle Method
The API key credential is encrypted and delivered directly through email to the user.
In both cases, once the credential is live on the client side (within the context of an iframe), it is readily available to stamp (authenticate) requests. See the enclave to end-user secure channel for more info on how we achieve secure delivery.
User Experience
OTP-based Authentication Flow
The flow begins with a new activity of type ACTIVITY_TYPE_INIT_OTP_AUTH
with these parameters:
otpType
: specify"OTP_TYPE_EMAIL"
contact
: user's email address (must match their registered email)emailCustomization
: optional parameters for customizing emailsuserIdentifier
: optional parameter for rate limiting (recommended for production)
After receiving the 6-digit code, users complete authentication with ACTIVITY_TYPE_OTP_AUTH
:
otpId
: ID from the init activityotpCode
: the 6-digit code received via emailtargetPublicKey
: public key for credential encryptionapiKeyName
: optional name (defaults toOTP Auth - <Timestamp>
)expirationSeconds
: optional validity window (defaults to 15 minutes)invalidateExisting
: optional boolean to invalidate previous OTP Auth API keys
Credential Bundle Authentication Flow
This alternative method uses ACTIVITY_TYPE_EMAIL_AUTH
with these parameters:
email
: user's email address (must match their registered email)targetPublicKey
: public key for credential encryptionapiKeyName
: optional name (defaults toEmail Auth - <Timestamp>
)expirationSeconds
: optional validity window (defaults to 15 minutes)emailCustomization
: optional parameters for customizing emailsinvalidateExisting
: optional boolean to invalidate previous Email Auth API keys
Recovery Flow
For account recovery scenarios, users can initiate a recovery-specific flow using the ACTIVITY_TYPE_INIT_USER_EMAIL_RECOVERY
activity type, which requires:
email
: the email of the user needing recovery (must match their registered email)targetPublicKey
: the public key for recovery credential encryption
The recovery process consists of two phases:
- Initiation: Generates a temporary recovery credential and sends it via email
- Finalization: User decrypts the recovery credential and uses it to sign an
ACTIVITY_TYPE_RECOVER_USER
activity, which can add new authenticators to regain account access
Authorization
Authorization is managed through our policy engine:
Authentication
Both OTP-based and credential bundle authentication activities:
- Can be performed by root users and users with proper policy authorization
- Require the respective feature to be enabled in the organization and sub-organization
- Can target any user in the organization or sub-organizations
Specifically:
- For OTP-based auth:
ACTIVITY_TYPE_INIT_OTP_AUTH
andACTIVITY_TYPE_OTP_AUTH
- For credential bundle auth:
ACTIVITY_TYPE_EMAIL_AUTH
Recovery
ACTIVITY_TYPE_INIT_USER_EMAIL_RECOVERY
:- Initiates the recovery process
- Requires proper authorization via policies
- Can target any user in the organization or sub-organizations
ACTIVITY_TYPE_RECOVER_USER
:- Must be signed by the recovery credential received via email
- Users can add credentials to their own user when authenticated
- Recovery credentials expire after 15 minutes
- Only the most recent recovery credential remains valid
- Users can add new authenticators to regain account access when authenticated with a recovery credential
Implementation in Sub-organizations
Both authentication methods and recovery work seamlessly with sub-organizations.
Example Implementations
For implementation details:
Implementation in Organizations
For organizations accessed via dashboard:
- Ensure the required features are enabled:
FEATURE_NAME_OTP_EMAIL_AUTH
for OTP-based authenticationFEATURE_NAME_EMAIL_AUTH
for credential bundle authentication- Recovery features if needed
- Users initiating the request must have appropriate permissions
Opting Out
Organizations can disable email-based features if their security model requires it:
Use ACTIVITY_TYPE_REMOVE_ORGANIZATION_FEATURE
to disable:
FEATURE_NAME_OTP_EMAIL_AUTH
for OTP-based authenticationFEATURE_NAME_EMAIL_AUTH
for credential bundle authenticationFEATURE_NAME_EMAIL_RECOVERY
for recovery
When creating sub-organizations, use:
disableOtpEmailAuth
parameter for OTP-based authenticationdisableEmailAuth
parameter for credential bundle authenticationdisableEmailRecovery
parameter for recovery
Implementation Notes
- Users are limited to:
- 10 long-lived API keys
- 10 expiring API keys (oldest are discarded when limit is reached)
For Top-level Organizations
- Both authentication methods are disabled by default
- Must be enabled via
ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE
For Sub-organizations
- Both authentication methods are enabled by default
- Can be disabled during creation using
CreateSubOrganizationIntentV7
activity parameters
Example of enabling OTP-based Email Auth:
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_OTP_EMAIL_AUTH"
}
}' --organization <YOUR-ORG-ID>
Example of enabling credential bundle Email Auth:
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_EMAIL_AUTH"
}
}' --organization <YOUR-ORG-ID>