Skip to content

Commit d49e460

Browse files
committed
feat(docs): add wrapped-keys docs
1 parent 9b4fe96 commit d49e460

File tree

3 files changed

+292
-2
lines changed

3 files changed

+292
-2
lines changed

docs/docs.json

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@
7979
"pages": [
8080
"sdk/auth-context-consumption/pkp-sign",
8181
"sdk/auth-context-consumption/execute-js",
82-
"sdk/auth-context-consumption/encrypt-and-decrypt"
82+
"sdk/auth-context-consumption/encrypt-and-decrypt",
83+
"sdk/auth-context-consumption/wrapped-keys"
8384
]
8485
},
8586
{
@@ -116,6 +117,22 @@
116117
"pages": [
117118
"sdk/sdk-reference/networks/functions/withOverrides"
118119
]
120+
},
121+
{
122+
"group": "@lit-protocol/wrapped-keys",
123+
"pages": [
124+
"sdk/sdk-reference/wrapped-keys/index",
125+
"sdk/sdk-reference/wrapped-keys/functions/generatePrivateKey",
126+
"sdk/sdk-reference/wrapped-keys/functions/exportPrivateKey",
127+
"sdk/sdk-reference/wrapped-keys/functions/importPrivateKey",
128+
"sdk/sdk-reference/wrapped-keys/functions/getEncryptedKey",
129+
"sdk/sdk-reference/wrapped-keys/functions/listEncryptedKeyMetadata",
130+
"sdk/sdk-reference/wrapped-keys/functions/storeEncryptedKey",
131+
"sdk/sdk-reference/wrapped-keys/functions/storeEncryptedKeyBatch",
132+
"sdk/sdk-reference/wrapped-keys/functions/batchGeneratePrivateKeys",
133+
"sdk/sdk-reference/wrapped-keys/functions/signMessageWithEncryptedKey",
134+
"sdk/sdk-reference/wrapped-keys/functions/signTransactionWithEncryptedKey"
135+
]
119136
}
120137
]
121138
},
@@ -129,7 +146,8 @@
129146
{
130147
"group": "Guides",
131148
"pages": [
132-
"guides/lit-action-sign-as-action"
149+
"guides/lit-action-sign-as-action",
150+
"guides/server-sessions"
133151
]
134152
},
135153
{

docs/guides/server-sessions.mdx

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
---
2+
title: "Server Sessions"
3+
description: "Delegate a PKP to an ephemeral session key and hand that scoped capability to backend services that mint fresh session signatures on demand."
4+
---
5+
6+
# Overview
7+
8+
Some integrations need a backend or serverless worker to execute Lit actions long after a user has left the client. Instead of caching `pkpSessionSigs` (which expire quickly and can become invalid when nodes join or leave the network), you can delegate the PKP to a session key and send the **session keypair plus delegation auth signature** to the server. The server then recreates the auth context and generates short-lived session signatures immediately before each request.
9+
10+
This pattern keeps the delegation scoped (resources and expiration are enforced by the delegation) while avoiding the flakiness that comes from reusing stale session signatures.
11+
12+
# Workflow
13+
14+
1. **Client generates a session keypair** with `generateSessionKeyPair()`.
15+
2. **Client mints a delegation auth signature** with `authManager.generatePkpDelegationAuthSig`, scoping the allowed abilities and expiration.
16+
3. **Client sends the bundle** `{ sessionKeyPair, delegationAuthSig, pkpPublicKey }` to the server over a secure channel.
17+
4. **Server restores an auth context** using `authManager.createPkpAuthContextFromPreGenerated`.
18+
5. **Server issues fresh session signatures on demand** (e.g., `authManager.createPkpSessionSigs`) immediately before calling SDK helpers such as the wrapped-keys API or `pkpSign`.
19+
20+
# Client hand-off example
21+
22+
```ts
23+
import {
24+
createAuthManager,
25+
generateSessionKeyPair,
26+
} from '@lit-protocol/auth';
27+
28+
const sessionKeyPair = generateSessionKeyPair();
29+
30+
const delegationAuthSig = await authManager.generatePkpDelegationAuthSig({
31+
pkpPublicKey,
32+
authData,
33+
sessionKeyPair,
34+
authConfig: {
35+
resources: [
36+
['pkp-signing', '*'],
37+
['lit-action-execution', '*'],
38+
['access-control-condition-decryption', '*'],
39+
],
40+
expiration: new Date(Date.now() + 15 * 60 * 1000).toISOString(),
41+
},
42+
litClient: litClient,
43+
});
44+
45+
const envelope = JSON.stringify({
46+
pkpPublicKey,
47+
payload: Buffer.from(
48+
JSON.stringify({ sessionKeyPair, delegationAuthSig }),
49+
'utf8'
50+
).toString('base64url'),
51+
});
52+
```
53+
54+
# Server restore example
55+
56+
```ts
57+
import {
58+
createAuthManager,
59+
storagePlugins,
60+
validateDelegationAuthSig,
61+
} from '@lit-protocol/auth';
62+
import { createLitClient } from '@lit-protocol/lit-client';
63+
64+
const parsedEnvelope = JSON.parse(envelope) as {
65+
pkpPublicKey: string;
66+
payload: string;
67+
};
68+
69+
const decodedPayload = JSON.parse(
70+
Buffer.from(parsedEnvelope.payload, 'base64url').toString('utf8')
71+
) as {
72+
sessionKeyPair: typeof sessionKeyPair;
73+
delegationAuthSig: typeof delegationAuthSig;
74+
};
75+
76+
validateDelegationAuthSig({
77+
delegationAuthSig: decodedPayload.delegationAuthSig,
78+
sessionKeyUri: decodedPayload.sessionKeyPair.publicKey,
79+
});
80+
81+
const serverLitClient = await createLitClient({ network: resolvedNetwork });
82+
const serverAuthManager = createAuthManager({
83+
storage: storagePlugins.localStorageNode({
84+
appName: 'server-session-demo',
85+
networkName: resolvedNetwork.name,
86+
storagePath: './.server-session-cache',
87+
}),
88+
});
89+
90+
const authContext =
91+
await serverAuthManager.createPkpAuthContextFromPreGenerated({
92+
pkpPublicKey: parsedEnvelope.pkpPublicKey,
93+
sessionKeyPair: decodedPayload.sessionKeyPair,
94+
delegationAuthSig: decodedPayload.delegationAuthSig,
95+
});
96+
97+
// ONly call this when the downstream API explicitly requires session sigs
98+
const pkpSessionSigs = await serverAuthManager.createPkpSessionSigs({
99+
sessionKeyPair: decodedPayload.sessionKeyPair,
100+
pkpPublicKey: parsedEnvelope.pkpPublicKey,
101+
delegationAuthSig: decodedPayload.delegationAuthSig,
102+
litClient: serverLitClient,
103+
});
104+
105+
await serverLitClient.chain.ethereum.pkpSign({
106+
authContext,
107+
pubKey: parsedEnvelope.pkpPublicKey,
108+
toSign: 'hello from server reuse',
109+
});
110+
```
111+
112+
<Note>
113+
Only call `createPkpSessionSigs` when the downstream API explicitly requires the session sigs (for example, the wrapped-keys service).
114+
</Note>
115+
116+
# Security considerations
117+
118+
- **Treat the session keypair like a secret.** Whoever holds the private key can mint new session signatures until the delegation expires.
119+
- **Scope the delegation.** Restrict resources to the minimal Lit resources needed and set conservative expirations.
120+
- **Rotate on failure.** If a node joins or leaves the network the server can simply regenerate session signatures with the current handshake; if that fails, request a fresh delegation from the client.
121+
122+
# When to use this pattern
123+
124+
- Long-running workflows where session signatures might expire before all steps finish (e.g., Bitcoin transactions that need multiple confirmations).
125+
- Server-driven orchestration that must run without a browser tab staying open.
126+
- Integrations that want to avoid caching `pkpSessionSigs`, but still need durable delegated access.
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
---
2+
title: "Wrapped Keys"
3+
description: "Manage generated or imported keys through Lit’s wrapped-keys service by delegating a PKP session and calling the specialised APIs for EVM and Solana."
4+
---
5+
6+
# Overview
7+
8+
Wrapped keys let you generate, import, store, and use non-PKP private keys while keeping them encrypted by the Lit Network. The `@lit-protocol/wrapped-keys` package exposes helper APIs that run curated Lit Actions via `executeJs` for you so that signed messages or transactions never leave the Lit node unless you explicitly export the key material.
9+
10+
Unlike the Core API flows (`pkpSign`, `executeJs`, `encryptAndDecrypt`) that accept an `authContext` directly, the wrapped-keys APIs expect a PKP session signature bundle (`pkpSessionSigs`). This keeps the SDK compatible with the v7 infrastructure and Lambda/serverless deployments that pass session materials between runtimes. Mint the bundle with `authManager.createPkpSessionSigs` as shown below.
11+
12+
# How the flow differs from other Core API methods
13+
14+
- **Why generate a delegation auth sig?**
15+
You delegate your PKP to an ephemeral session key so the wrapped-keys Lit Actions can execute without presenting your long-lived auth credentials. The delegation constrains the permissions (`pkp-signing`, `lit-action-execution`, `access-control-condition-decryption`) and sets an expiry window, limiting blast radius if the session key is ever leaked.
16+
17+
- **Why supply PKP session signatures?**
18+
Wrapped-keys endpoints reuse the same session bundle across all networks (for example, Lambda functions in the v7 stack). Provide `pkpSessionSigs` produced by `authManager.createPkpSessionSigs` so the Lit nodes can verify the delegated permissions before executing the action.
19+
20+
- **Controlling network spend**
21+
Because every wrapped-keys helper ultimately calls `executeJs`, you can supply an optional `userMaxPrice` to cap how much a caller is willing to pay for node execution (mirroring the parameter available on the core `executeJs` API).
22+
23+
- **Optional: bundle Lit Action source**
24+
By default the SDK references IPFS CIDs. To remove the IPFS dependency, inject the Lit Action source code at runtime:
25+
26+
```ts
27+
import { api as wrappedKeysApi, config as wrappedKeysConfig } from '@lit-protocol/wrapped-keys';
28+
import {
29+
litActionRepository,
30+
litActionRepositoryCommon,
31+
} from '@lit-protocol/wrapped-keys-lit-actions';
32+
33+
wrappedKeysConfig.setLitActionsCode(litActionRepository);
34+
wrappedKeysConfig.setLitActionsCodeCommon(litActionRepositoryCommon);
35+
```
36+
37+
# Session material workflow
38+
39+
```ts
40+
import { createAuthManager, generateSessionKeyPair } from '@lit-protocol/auth';
41+
import { api as wrappedKeysApi } from '@lit-protocol/wrapped-keys';
42+
43+
const authManager = createAuthManager();
44+
const litClient = await createLitClient({ network: resolvedNetwork });
45+
46+
// 1. Ephemeral signer that will front the PKP for wrapped-key actions
47+
const sessionKeyPair = generateSessionKeyPair();
48+
49+
// 2. Delegate the PKP to the session key with explicit Lit resources and expiry
50+
const delegationAuthSig = await authManager.generatePkpDelegationAuthSig({
51+
pkpPublicKey,
52+
authData,
53+
sessionKeyPair,
54+
authConfig: {
55+
resources: [
56+
['pkp-signing', '*'],
57+
['lit-action-execution', '*'],
58+
['access-control-condition-decryption', '*'],
59+
],
60+
expiration: new Date(Date.now() + 15 * 60 * 1000).toISOString(),
61+
},
62+
litClient,
63+
});
64+
65+
// 3. Produce the SessionSigsMap required by every wrapped-keys API call
66+
const pkpSessionSigs = await authManager.createPkpSessionSigs({
67+
sessionKeyPair,
68+
pkpPublicKey,
69+
delegationAuthSig,
70+
litClient,
71+
});
72+
73+
// 4. Call wrapped-keys APIs with the session signatures
74+
const { id } = await wrappedKeysApi.generatePrivateKey({
75+
pkpSessionSigs,
76+
litClient,
77+
network: 'evm',
78+
memo: 'wallet for gasless relays',
79+
userMaxPrice: 1000n, // optional cap on per-request spend
80+
});
81+
```
82+
83+
<Note>
84+
Wrapped-keys calls need `pkpSessionSigs` explicitly. Other Lit APIs that accept an `authContext` (for example `executeJs` or `pkpSign`) creates session signatures internally, so you do not need to export it when you are not touching wrapped keys.
85+
</Note>
86+
87+
Need a backend to create fresh session signatures on demand? Follow the [server sessions guide](/guides/server-sessions) to delegate a session key and let the server recreate `pkpSessionSigs` per request.
88+
89+
# Example usage
90+
91+
## Generate and sign on EVM
92+
93+
```ts
94+
const { id, generatedPublicKey } = await wrappedKeysApi.generatePrivateKey({
95+
pkpSessionSigs,
96+
litClient,
97+
network: 'evm',
98+
memo: 'lit',
99+
});
100+
101+
// Export once if you need the raw private key
102+
const { decryptedPrivateKey } = await wrappedKeysApi.exportPrivateKey({
103+
pkpSessionSigs,
104+
litClient,
105+
network: 'evm',
106+
id,
107+
});
108+
109+
// Sign an EVM transaction without revealing the key outside the Lit nodes
110+
const serializedTx = await wrappedKeysApi.signTransactionWithEncryptedKey({
111+
pkpSessionSigs,
112+
litClient,
113+
network: 'evm',
114+
id,
115+
unsignedTransaction: {
116+
chain: 'yellowstone',
117+
chainId: 175188,
118+
toAddress: '0x0000000000000000000000000000000000000000',
119+
value: '0',
120+
},
121+
broadcast: false,
122+
});
123+
```
124+
125+
## Generate and sign on Solana
126+
127+
```ts
128+
const { id, publicKey } = await wrappedKeysApi.generatePrivateKey({
129+
pkpSessionSigs,
130+
litClient,
131+
network: 'solana',
132+
memo: 'vault signer',
133+
});
134+
135+
const signature = await wrappedKeysApi.signMessageWithEncryptedKey({
136+
pkpSessionSigs,
137+
litClient,
138+
network: 'solana',
139+
id,
140+
messageToSign: 'hello from wrapped keys',
141+
});
142+
```
143+
144+
# API catalogue
145+
146+
See the full reference for every helper at [`sdk-reference/wrapped-keys`](./sdk-reference/wrapped-keys/index.mdx).

0 commit comments

Comments
 (0)