-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Simplifying delegated access steps #265
Conversation
@@ -67,9 +83,7 @@ To set up delegated access, here’s one example of how you can create a limited | |||
} | |||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we could maybe insert here a code example of how to create such a sub-org on the server side with an email only end user:
import { Turnkey } from "@turnkey/sdk-server";
import dotenv from "dotenv";
dotenv.config();
// Initialize the Turnkey Server Client on the server-side
const turnkeyServer = new Turnkey({
apiBaseUrl: "https://api.turnkey.com",
apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY,
apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY,
defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID,
}).apiClient();
// To create an API key programatically check https://github.com/tkhq/sdk/blob/main/examples/kitchen-sink/src/sdk-server/createApiKey.ts
const publicKey = "<delegator_api_public_key>";
const curveType = "API_KEY_CURVE_P256"; // this is the default
const apiKeys = [
{
apiKeyName: "Delegated - API Key",
publicKey,
curveType,
},
];
const subOrg = await turnkeyServer.createSubOrganization({
organizationId: process.env.TURNKEY_ORGANIZATION_ID,
subOrganizationName: `Sub Org - With Delegator`,
rootUsers: [
{
userName: "Delegator User",
userEmail: "...",
apiKeys,
authenticators: [],
oauthProviders: []
},
{
userName: "End User",
userEmail: "...",
apiKeys: [],
authenticators: [],
oauthProviders: []
},
],
rootQuorumThreshold: 1,
wallet: {
"walletName": "Default ETH Wallet",
"accounts": [
{
"curve": "CURVE_SECP256K1",
"pathFormat": "PATH_FORMAT_BIP32",
"path": "m/44'/60'/0'/0/0",
"addressFormat": "ADDRESS_FORMAT_ETHEREUM"
}
]
},
});
console.log("sub-org id:", subOrg.subOrganizationId);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this could be totally valuable to add in!
@@ -113,12 +110,10 @@ Here’s one example, creating a Delegated Account that only has permission to s | |||
} | |||
``` |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could reference this example on how to create a policy on the server side:
https://github.com/tkhq/sdk/blob/main/examples/kitchen-sink/src/sdk-server/createPolicy.ts
And for clarity mention what should be the api key and org id:
API_PUBLIC_KEY / API_PRIVATE_KEY -> this is your delegator account api key added in the sub-organization above
ORGANIZATION_ID -> this is your newly created sub-organization id
* Create a new policy that explicitly grants the Service Account permission to delete users. This is necessary because, once removed from the Root Quorum, the Service Account will have no permissions by default. | ||
* [Update the root quorum](/api-reference/organizations/update-root-quorum) to remove the Service Account from the root quorum | ||
* Delete the Service Account user from the organization | ||
* [Update the root quorum](/api-reference/organizations/update-root-quorum) to remove the Delegated Account from the root quorum | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How to update the root quorum (same notes about the api key and org id as for the create policy above):
https://github.com/tkhq/sdk/blob/main/examples/kitchen-sink/src/sdk-server/updateRootQuorum.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should just put together an example in the sdk repo for this use-case and link it at the top? Or if you think its concise enough the code could just be pasted all here in one block?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@zkharit here's the full thing - mind having a look pls:
import { Turnkey } from "@turnkey/sdk-server";
import dotenv from "dotenv";
dotenv.config();
async function main() {
// Initialize a Turnkey client using the parent organization
// used to create the sub-organization with the two users in it
const turnkeyClient = new Turnkey({
apiBaseUrl: "https://api.turnkey.com",
apiPrivateKey: process.env.TURNKEY_API_PRIVATE_KEY,
apiPublicKey: process.env.TURNKEY_API_PUBLIC_KEY,
defaultOrganizationId: process.env.TURNKEY_ORGANIZATION_ID,
}).apiClient();
// for extra clarity, using a separate API key than the one used by the parent org
// make sure to have both DELEGATOR_API_PUBLIC_KEY and DELEGATOR_API_PRIVATE_KEY added in .env
const curveType = "API_KEY_CURVE_P256";
const apiKeys = [
{
apiKeyName: "Delegated - API Key",
publicKey: process.env.DELEGATOR_API_PUBLIC_KEY,
curveType,
},
];
const subOrg = await turnkeyClient.createSubOrganization({
organizationId: process.env.TURNKEY_ORGANIZATION_ID,
subOrganizationName: `Sub Org - With Delegator`,
rootUsers: [
{
userName: "Delegator User",
userEmail: "[email protected]",
apiKeys,
authenticators: [],
oauthProviders: []
},
{
userName: "End User",
userEmail: "[email protected]",
apiKeys: [],
authenticators: [],
oauthProviders: []
},
],
rootQuorumThreshold: 1,
wallet: {
"walletName": "Default ETH Wallet",
"accounts": [
{
"curve": "CURVE_SECP256K1",
"pathFormat": "PATH_FORMAT_BIP32",
"path": "m/44'/60'/0'/0/0",
"addressFormat": "ADDRESS_FORMAT_ETHEREUM"
}
]
},
});
console.log("sub-org id:", subOrg.subOrganizationId);
// Initializing the Turkey client used by the Delegator activities
// Notice the subOrganizationId created above
const turnkeyDelegator = new Turnkey({
apiBaseUrl: "https://api.turnkey.com",
apiPrivateKey: process.env.DELEGATOR_API_PRIVATE_KEY,
apiPublicKey: process.env.DELEGATOR_API_PUBLIC_KEY,
defaultOrganizationId: subOrg.subOrganizationId,
}).apiClient();
// Creating a policy for the Delegated account
const delegator_userid = subOrg.rootUserIds[0];
const policyName = "Allow Delegated Account to sign transactions to specific address";
const effect = "EFFECT_ALLOW";
const consensus = `approvers.any(user, user.id == '${delegator_userid}')`;
const condition = `eth.tx.to == '${process.env.RECIPIENT_ADDRESS}'`;
const notes = "";
const { policyId } = await turnkeyDelegator.createPolicy({
policyName,
condition,
consensus,
effect,
notes,
});
console.log(
[
`New policy created!`,
`- Name: ${policyName}`,
`- Policy ID: ${policyId}`,
`- Effect: ${effect}`,
`- Consensus: ${consensus}`,
`- Condition: ${condition}`,
``,
].join("\n"),
);
// Remove the Delegated Account from the root quorum
const RootQuorum = await turnkeyDelegator.updateRootQuorum({
threshold: 1,
userIds: [subOrg.rootUserIds[1]], // retain the end user
});
console.log("Root Quorum updated! :", RootQuorum);
}
main().catch((error) => {
console.error(error);
process.exit(1);
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks awesome, might want to use <user-email-addres>
or something similar for the email address, but this is a great snippet here!
Surface changes to improve clarify of delegated access setup