-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
95a6adf
commit b7c3485
Showing
8 changed files
with
192 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,7 @@ | |
sidebar_position: 8 | ||
slug: /faq | ||
--- | ||
|
||
# FAQ | ||
|
||
### Why do you require a public / private key pair to access Turnkey API? | ||
|
@@ -38,26 +39,28 @@ We have limits on the number of resources within a single organization to avoid | |
|
||
Currently, the resource limits within a single organization are as follows: | ||
|
||
| Resource | Maximum number allowed | | ||
| :---------------------- | :--------------------- | | ||
| Private keys | 1,000 | | ||
| Wallets | 100 | | ||
| Users | 100 | | ||
| Policies | 100 | | ||
| Invitations | 100 | | ||
| Tags | 100 | | ||
| Authenticators per user | 10 | | ||
| API keys per user | 10 | | ||
| Sub-Organizations | unlimited | | ||
| Resource | Maximum number allowed | | ||
| :----------------------------- | :--------------------- | | ||
| Private keys | 1,000 | | ||
| Wallets | 100 | | ||
| Users | 100 | | ||
| Policies | 100 | | ||
| Invitations | 100 | | ||
| Tags | 100 | | ||
| Authenticators per user | 10 | | ||
| API keys per user (long-lived) | 10 | | ||
| API keys per user (expiring) | 10 | | ||
| Sub-Organizations | unlimited | | ||
|
||
If you are approaching any of these limits in your implementation and require support, reach out to the Turnkey team (<[email protected]>). | ||
|
||
### Do you have any rate limits in place in your public API? | ||
|
||
Our public API currently limits users to a maximum of 60 RPS (Requests Per Second). Specific headers are returned to indicate current quota: | ||
* `ratelimit-limit`: indicates the total quota (60) | ||
* `ratelimit-remaining`: indicates the current quota | ||
* `x-rate-limit-request-forwarded-for` and `x-rate-limit-request-remote-addr`: echo back your remote IP and forwarded-for IP for debugging purposes | ||
|
||
- `ratelimit-limit`: indicates the total quota (60) | ||
- `ratelimit-remaining`: indicates the current quota | ||
- `x-rate-limit-request-forwarded-for` and `x-rate-limit-request-remote-addr`: echo back your remote IP and forwarded-for IP for debugging purposes | ||
|
||
When rate limits are exceeded, an error with HTTP 429 is returned with the following message: `Too many requests. Please wait and try again in a few seconds`. | ||
|
||
|
@@ -104,16 +107,16 @@ We require a recent timestamp in the `timestampMs` field for each new activity s | |
|
||
Our secure enclaves have their own, independent, secure source of time. We currently require request timestamps to be **less than an hour old**, and **up to 5 minutes in the future**. | ||
|
||
### How do pricing and billing work? | ||
### How do pricing and billing work? | ||
|
||
Turnkey is priced per signature, i.e. any transaction or raw payload successfully signed by a private key created on Turnkey. Turnkey offers 25 free signatures each month. To execute more than 25 transactions in a given month, you are required to have a credit card on file or active enterprise plan on your account. To upgrade your plan, navigate to Account Settings from the menu in the top right-hand corner in the Turnkey dashboard and follow the instructions. | ||
Turnkey is priced per signature, i.e. any transaction or raw payload successfully signed by a private key created on Turnkey. Turnkey offers 25 free signatures each month. To execute more than 25 transactions in a given month, you are required to have a credit card on file or active enterprise plan on your account. To upgrade your plan, navigate to Account Settings from the menu in the top right-hand corner in the Turnkey dashboard and follow the instructions. | ||
|
||
For more information about pricing and billing, check out the [pricing page](https://www.turnkey.com/pricing). | ||
|
||
### Where else can I get help with my Turnkey implementation? | ||
|
||
If you get stuck or have a one-off question, post it to our [developer forum](https://github.com/orgs/tkhq/discussions) or reach out directly to [email protected]. Teams that are looking for more in-depth integration support can upgrade to an Enterprise plan via [email protected]. | ||
If you get stuck or have a one-off question, post it to our [developer forum](https://github.com/orgs/tkhq/discussions) or reach out directly to [email protected]. Teams that are looking for more in-depth integration support can upgrade to an Enterprise plan via [email protected]. | ||
|
||
### Is my country supported? | ||
|
||
Turnkey is not currently available to users in any countries currently subject to US OFAC sanctions. | ||
Turnkey is not currently available to users in any countries currently subject to US OFAC sanctions. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
--- | ||
sidebar_position: 7 | ||
description: Learn about Email Auth on Turnkey | ||
slug: /getting-started/email-auth | ||
--- | ||
# Email Auth | ||
|
||
Email Auth lets a user authenticate their Turnkey account via email. | ||
|
||
## User Experience | ||
|
||
Email auth starts with a new activity posted to Turnkey. This activity has the type `ACTIVITY_TYPE_EMAIL_AUTH` and takes the following as parameters: | ||
* `email`: the email of the user who would like to authenticate. This email must be the email already attached to the user in organization data (i.e., previously approved by the user). This prevents malicious account takeover. If you try to pass a different email address, the activity will fail. | ||
* `targetPublicKey`: the public key to which the recovery credential is encrypted (more on this later) | ||
* `apiKeyName`: an optional name for the API Key. If none is provided, we will default to `Email Auth - <Timestamp>` | ||
* `expirationSeconds`: an optional window (in seconds) indicating how long the API Key should last. Default to 30 minutes. | ||
* `emailCustomization`: optional parameters for customizing emails. If not provided, use defaults. This is currently a WIP. 🚧 | ||
|
||
This activity generates a new API key pair (an "auth credential"), saves the public key in organization data under the target user, and sends an email with the encrypted auth credential: | ||
|
||
<img src="/img/auth_email.png" width="420" /> | ||
|
||
Calling email auth requires proper permissions via policies or being a parent organization. See [Authorization](#authorization) for more details. | ||
|
||
## Authorization | ||
|
||
Authorization for email auth is based on our usual activity authorization: our [policy engine](../policy-management/Policy-overview.md) controls who can and cannot execute recovery-related activities. | ||
* `ACTIVITY_TYPE_EMAIL_AUTH` can be performed by the root user or by any user in an organization if authorized by policy, but **only if the feature is enabled**. The activity can target **any user** in this organization **or any sub-organization user**. The activity will fail if a parent user tries to perform email auth for a sub-organization which has [opted out of this feature](#opting-out-of-email-auth). | ||
|
||
<p style={{textAlign: 'center'}}> | ||
<img src="/img/diagrams/email_auth_authorization.png" width="500" height="200"/> | ||
</p> | ||
|
||
## Email recovery in your sub-organizations | ||
|
||
Email recovery works well with [sub-organizations](./Sub-Organizations.md). Our Demo Passkey Wallet application (https://wallet.tx.xyz) has recovery functionality integrated. We encourage you to try it (and look at [the code](https://github.com/tkhq/demo-passkey-wallet) if you're curious!). | ||
|
||
If you're looking for a more concrete guide, head to our [Sub-Organization Recovery implementation guide](../integration-guides/email-recovery-in-sub-organizations.md) for more details. | ||
|
||
## Email recovery in your organization | ||
|
||
If you want to use email recovery in the context of an organization accessed via our dashboard, we aren't ready yet. This is because we do not have a flow to enroll new passkeys and sign `RECOVER_USER` activities in our main dashboard. | ||
|
||
A workaround if you're a root user trying to perform recovery for one of your users: delete their user and re-invite them by email. It's not perfect because their new user ID will differ from their old one (which means policies might need an update). | ||
|
||
If you're a root user and you have lost access to your authenticators, **Turnkey cannot perform email recovery for you**. You need to create a fresh organization. | ||
|
||
## Opting out of email auth | ||
|
||
Similar to email recovery, depending on your threat model, it may be unacceptable to rely on email as an authentication factor. We envision this to be the case when an organization has a mature set of root users with multiple authenticators, or when a sub-organization "graduates" from one to many redundant passkeys or API keys. When you're ready, you can disable email auth with `ACTIVITY_TYPE_REMOVE_ORGANIZATION_FEATURE` (see Remove [Organization Feature](/api#tag/Features/operation/RemoveOrganizationFeature)). The feature name to remove is `FEATURE_NAME_EMAIL_AUTH`. | ||
|
||
If you _never_ want to have email recovery enabled, our `CREATE_SUB_ORGANIZATION` activity takes a `disableEmailAuth` boolean in its parameters. Set it to `true` and the sub-organization will be created without the organization feature. | ||
|
||
## Cryptographic details | ||
|
||
Unlike typical email recovery functionality, Turnkey's email recovery doesn't send unencrypted tokens via emails. This ensures no man-in-the-middle attack can happen: even if the content of the auth email is leaked, an attacker wouldn't be able to decrypt the auth credential. The following diagram summarizes the flow: | ||
|
||
<img src="/img/email_auth_cryptography.png" /> | ||
|
||
Our email auth flow works by anchoring auth in a **target encryption key** (TEK). This target encryption key is a standard P-256 key pair and can be created in many ways: completely offline, or online inside of script using the web crypto APIs. | ||
|
||
The public part of this key pair is passed as a parameter inside of a signed `EMAIL_AUTH` activity. The signature on the activity has to come from a user who is [authorized](#authorization) to initiate email auth. | ||
|
||
Our enclave creates a fresh P256 key pair ("auth credential") and encrypts the private key to the recovering user's TEK using the **Hybrid Public Key Encryption standard**, also known as **HPKE** or [RFC 9180](https://datatracker.ietf.org/doc/rfc9180/). | ||
|
||
Once the encrypted auth credential is received via email, it's decrypted where the target public key was originally created. The auth credential is then ready to be used to sign an activity, which is then submitted to Turnkey. | ||
|
||
## Implementation notes | ||
|
||
Users currently have a limit of 10 long-lived API keys, and 10 expiring API keys. In the case that the limit of expiring API keys is breached, the oldest (by creation date) will be discarded. | ||
|
||
NOTE: feature must be enabled. For top-level orgs, by default, Email Auth is not enabled. It must be enabled using a command like | ||
|
||
``` | ||
turnkey request --host api.turnkey.com --path /public/v1/submit/email_auth --body '{ | ||
"timestampMs": "'"$(date +%s)"'000", | ||
"type": "ACTIVITY_TYPE_SET_ORGANIZATION_FEATURE", | ||
"organizationId": "55205413-cbc2-4b46-94d7-899d3f299b40", | ||
"parameters": { | ||
"name": "FEATURE_NAME_EMAIL_AUTH" | ||
} | ||
}' --organization 55205413-cbc2-4b46-94d7-899d3f299b40 | ||
``` | ||
|
||
Suborgs have Email Auth enabled as a feature by default. It can be conveniently disabled during creation, using the `CreateSubOrganizationIntentV4` activity parameter `disableEmailAuth`. |
85 changes: 85 additions & 0 deletions
85
docs/integration-guides/email-auth-for-sub-organizations.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,85 @@ | ||
--- | ||
sidebar_position: 3 | ||
description: Learn about Email Auth on Turnkey | ||
slug: /integration-guides/sub-organization-auth | ||
--- | ||
# Sub-Organization Auth | ||
|
||
Email auth is a powerful feature to couple with [sub-organizations](../getting-started/Sub-Organizations.md) for your users. This approach empowers your users to authenticate their Turnkey in a simple way (via email!), while minimizing your involvement: we engineered this feature to ensure your organization is unable to take over sub-organizations even if it wanted to. | ||
|
||
<!-- TODO | ||
Our Demo Passkey Wallet application (https://wallet.tx.xyz) will soon have email auth functionality integrated. We encourage you to try it (and look at [the code](https://github.com/tkhq/demo-passkey-wallet)) before diving into your own implementation. --> | ||
|
||
## Pre-requisites | ||
|
||
Make sure you have set up your primary Turnkey organization with at least one API user that can programmatically initiate email auth. Check out our [Quickstart guide](../getting-started/Quickstart.md) 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 JSON | ||
{ | ||
"effect": "EFFECT_ALLOW", | ||
"consensus": "approvers.any(user, user.id == '<YOUR_API_USER_ID>')", | ||
"condition": "activity.resource == 'AUTH' && activity.action == 'CREATE'" | ||
} | ||
``` | ||
|
||
## Helper packages | ||
|
||
* We have released open-source code to create target encryption keys, decrypt recovery credentials, and sign Turnkey activities. We've deployed this a static HTML page hosted on `auth.turnkey.com` meant to be embedded as an iframe element (see the code [here](https://github.com/tkhq/frames)). This ensures the recovery credentials are encrypted to keys that your organization doesn't have access to (because they live in the iframe, on a separate domain) | ||
* We have also built a package to help you insert this iframe and interact with it in the context of email recovery: [`@turnkey/iframe-stamper`](https://www.npmjs.com/package/@turnkey/iframe-stamper) | ||
|
||
In the rest of this guide we'll assume you are using these helpers. | ||
|
||
## Email Auth step-by-step | ||
|
||
Here's a diagram summarizing the email auth flow step-by-step ([direct link](/img/email_auth_steps.png)): | ||
|
||
<img src="/img/email_auth_steps.png" /> | ||
|
||
Let's review these steps in detail: | ||
|
||
1. User on `yoursite.xyz` clicks "auth", and a new auth UI is shown. We recommend this auth UI be a new hosted page of your site or application, which contains language explaining to the user what steps they will need to take next to successfully authenticate. While the UI is in a loading state your frontend uses [`@turnkey/iframe-stamper`](https://www.npmjs.com/package/@turnkey/iframe-stamper) to insert a new iframe element: | ||
```js | ||
const iframeStamper = new IframeStamper({ | ||
iframeUrl: "https://auth.turnkey.com", | ||
// Configure how the iframe element is inserted on the page | ||
iframeContainerId: "your-container", | ||
iframeElementId: "turnkey-iframe", | ||
}); | ||
|
||
// Inserts the iframe in the DOM. This creates the new encryption target key | ||
const publicKey = await iframeStamper.init(); | ||
``` | ||
<!-- TODO: describe customization as well --> | ||
2. Your code receives the iframe public key and shows the auth form, and the user enters their email address. | ||
3. Your app can now create and sign a new `EMAIL_AUTH` activity with the user email and the iframe public key in the parameters. Optional arguments include a custom name for the API key, and a specific duration (denoted in seconds) for it. Note: you'll need to retrieve the sub-organization ID based on the user email. | ||
4. Email is received by the user. | ||
5. User copies and pastes their auth code into your app. Remember: this code is an encrypted credential which can only be decrypted within the iframe. | ||
6. Your app injects the auth code into the iframe for decryption: | ||
```js | ||
await iframeStamper.injectCredentialBundle(code); | ||
``` | ||
7. At this point, the user is authenticated! Your app should use [`@turnkey/iframe-stamper`](https://www.npmjs.com/package/@turnkey/iframe-stamper) to sign a new activity, e.g. `CREATE_WALLET`: | ||
```js | ||
// New client instantiated with our iframe stamper | ||
const client = new TurnkeyClient( | ||
{ baseUrl: "https://api.turnkey.com" }, | ||
iframeStamper, | ||
); | ||
// Sign and submits the CREATE_WALLET activity | ||
const response = await client.recoverUser({ | ||
type: "ACTIVITY_TYPE_CREATE_WALLET", | ||
timestampMs: String(Date.now()), | ||
organizationId: authResponse.organizationId, | ||
parameters: { | ||
walletName: "Default Wallet", | ||
accounts: [{ | ||
curve: "CURVE_SECP256K1", | ||
pathFormat: "PATH_FORMAT_BIP32", | ||
path: "m/44'/60'/0'/0/0", | ||
addressFormat: "ADDRESS_FORMAT_ETHEREUM", | ||
}], | ||
}, | ||
}); | ||
``` | ||
Congrats! You've succcessfully performed Email Auth! 🥳 |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.