Is there an existing issue for this?
SDK version
Lit Network
Description of the bug/issue
When working with multiple PKPs sequentially, session signature generation fails because the SDK uses a globally cached wallet signature that is not scoped to individual PKPs. This causes the second (and subsequent) PKP to incorrectly use the first PKP's cached authentication data.
Impact
- Multi-PKP applications: Cannot reliably use multiple PKPs in the same session
- Testing: Tests pass individually but fail when run sequentially
- Silent failure: No error during authentication; fails later with cryptic error message
- Error message:
"Access control conditions check failed" when attempting to use the PKP
Root Cause
File: packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts:353
getWalletSig = async ({ ... }: GetWalletSigProps): Promise<AuthSig> => {
let walletSig: AuthSig;
const storageKey = LOCAL_STORAGE_KEYS.WALLET_SIGNATURE; // ❌ Not PKP-specific
const storedWalletSigOrError = getStorageItem(storageKey);
// Retrieves cached signature without validating PKP context
if (storedWalletSigOrError.type !== EITHER_TYPE.ERROR) {
walletSig = JSON.parse(storedWalletSigOrError.result as string);
}
return walletSig!;
};
The cache key "lit-wallet-sig" is not scoped by PKP public key, so all PKPs share the same cached signature.
Additional Context
The same issue likely affects SESSION_KEY caching (line 238) which also uses a non-scoped storage key.
Related Code
- Cache key definitions:
packages/constants/src/lib/constants/constants.ts:1551-1559
- Storage utilities:
packages/misc-browser/src/lib/misc-browser.ts:21-70
Severity of the bug
Medium
Steps To Reproduce
import { LitNodeClient } from '@lit-protocol/lit-node-client';
import { EthWalletProvider } from '@lit-protocol/lit-auth-client';
// Test 1: Create first PKP
const authMethod1 = await EthWalletProvider.authenticate({
signer: wallet,
litNodeClient,
expiration,
});
const pkp1 = await api.pkp.mint.post({
authMethod: authMethod1,
scopes: [AUTH_METHOD_SCOPE.SignAnything],
});
const sessionSigs1 = await litNodeClient.getSessionSigs({
pkpPublicKey: pkp1.publicKey,
authNeededCallback: async () => { /* ... */ },
});
console.log('PKP1 Session Sig Address:', Object.values(sessionSigs1)[0].address);
// Output: "0x3D2870939c94FEC0aa94A78ff6a53FBF6b938aAc" ✅
// Test 2: Create second PKP (WITHOUT clearing localStorage)
const authMethod2 = await EthWalletProvider.authenticate({
signer: wallet,
litNodeClient,
expiration,
});
const pkp2 = await api.pkp.mint.post({
authMethod: authMethod2,
scopes: [AUTH_METHOD_SCOPE.SignAnything],
});
const sessionSigs2 = await litNodeClient.getSessionSigs({
pkpPublicKey: pkp2.publicKey,
authNeededCallback: async () => { /* ... */ },
});
console.log('PKP2 Session Sig Address:', Object.values(sessionSigs2)[0].address);
// Output: "0x3D2870939c94FEC0aa94A78ff6a53FBF6b938aAc" ❌ WRONG! Should be PKP2's address
// Bug: sessionSigs2 contains PKP1's address because it used cached signature
// Later operations fail:
await litNodeClient.executeJs({
sessionSigs: sessionSigs2, // ❌ Fails with "Access control conditions check failed"
code: `...`,
});
Expected Behavior
Each PKP should have its own cached wallet signature, or the cache should be invalidated when the PKP context changes.
Current Workaround
Manually clear localStorage between PKP operations:
localStorage.removeItem('lit-wallet-sig');
localStorage.removeItem('lit-session-key');
Link to code
- Affected Files:
packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts
packages/lit-auth-client/src/lib/providers/EthWalletProvider.ts
Anything else?
Suggested Fixes
Option 1: Scope cache key by PKP (Recommended)
const storageKey = pkpPublicKey
? `${LOCAL_STORAGE_KEYS.WALLET_SIGNATURE}-${pkpPublicKey}`
: LOCAL_STORAGE_KEYS.WALLET_SIGNATURE;
Option 2: Add validation
Check if cached signature matches current PKP context before reusing:
if (storedWalletSigOrError.type !== EITHER_TYPE.ERROR) {
const cached = JSON.parse(storedWalletSigOrError.result as string);
// Validate signature is for correct PKP
if (isValidForCurrentPKP(cached, pkpPublicKey)) {
walletSig = cached;
}
}
Option 3: Clear cache on new authentication
EthWalletProvider.authenticate() should clear stale cached signatures:
public static async authenticate({ ... }) {
// Clear previous PKP's cached signature
removeStorageItem(LOCAL_STORAGE_KEYS.WALLET_SIGNATURE);
removeStorageItem(LOCAL_STORAGE_KEYS.SESSION_KEY);
// ... rest of authentication
}
Is there an existing issue for this?
SDK version
Lit Network
Description of the bug/issue
When working with multiple PKPs sequentially, session signature generation fails because the SDK uses a globally cached wallet signature that is not scoped to individual PKPs. This causes the second (and subsequent) PKP to incorrectly use the first PKP's cached authentication data.
Impact
"Access control conditions check failed"when attempting to use the PKPRoot Cause
File:
packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.ts:353The cache key
"lit-wallet-sig"is not scoped by PKP public key, so all PKPs share the same cached signature.Additional Context
The same issue likely affects
SESSION_KEYcaching (line 238) which also uses a non-scoped storage key.Related Code
packages/constants/src/lib/constants/constants.ts:1551-1559packages/misc-browser/src/lib/misc-browser.ts:21-70Severity of the bug
Medium
Steps To Reproduce
Expected Behavior
Each PKP should have its own cached wallet signature, or the cache should be invalidated when the PKP context changes.
Current Workaround
Manually clear localStorage between PKP operations:
Link to code
packages/lit-node-client-nodejs/src/lib/lit-node-client-nodejs.tspackages/lit-auth-client/src/lib/providers/EthWalletProvider.tsAnything else?
Suggested Fixes
Option 1: Scope cache key by PKP (Recommended)
Option 2: Add validation
Check if cached signature matches current PKP context before reusing:
Option 3: Clear cache on new authentication
EthWalletProvider.authenticate()should clear stale cached signatures: