Session keys only work with CHIPI wallets - not ARGENT wallets. Make sure your wallet was created with walletType: "CHIPI".
Overview
Session keys allow your application to execute transactions on behalf of a user without requiring their owner private key for every action. This enables gasless, frictionless UX for gaming, DeFi automation, social apps, and more.
| Method | Description |
|---|
sessions.createSessionKey() | Generate a session keypair locally |
sessions.addSessionKeyToContract() | Register session on-chain |
sessions.revokeSessionKey() | Revoke a session key |
sessions.getSessionData() | Query session status |
executeTransactionWithSession() | Execute tx using session |
createSessionKey
Generate a session keypair locally. This is a synchronous operation that doesn’t make network calls.
const session = browserClient.sessions.createSessionKey({
encryptKey: "user-secure-pin",
durationSeconds: 3600, // 1 hour (default: 6 hours)
});
console.log(session);
// {
// publicKey: "0x...",
// encryptedPrivateKey: "...",
// validUntil: 1702500000
// }
// Store in client-side storage (NOT your database!)
localStorage.setItem('chipiSession', JSON.stringify(session));
Parameters
| Parameter | Type | Required | Description |
|---|
encryptKey | string | Yes | PIN to encrypt the session private key |
durationSeconds | number | No | Session duration in seconds (default: 21600 = 6 hours) |
Return Value
{
publicKey: string; // Session public key (hex)
encryptedPrivateKey: string; // AES encrypted with encryptKey
validUntil: number; // Unix timestamp (seconds)
}
Never store session keys in your backend database. Store only in client-side secure storage (localStorage, sessionStorage, or platform-specific secure storage).
addSessionKeyToContract
Register a session key on the CHIPI wallet smart contract. This requires the owner’s signature (one-time setup per session).
const bearerToken = await getBearerToken();
const txHash = await browserClient.sessions.addSessionKeyToContract({
encryptKey: "user-secure-pin",
wallet: {
publicKey: wallet.publicKey,
encryptedPrivateKey: wallet.encryptedPrivateKey,
walletType: "CHIPI",
},
sessionConfig: {
sessionPublicKey: session.publicKey,
validUntil: session.validUntil,
maxCalls: 100, // Maximum transactions allowed
allowedEntrypoints: [], // Empty = all functions allowed
},
}, bearerToken);
console.log("Session registered:", txHash);
Parameters
| Parameter | Type | Required | Description |
|---|
encryptKey | string | Yes | Owner’s PIN to sign the registration |
wallet | WalletData | Yes | Wallet object with publicKey, encryptedPrivateKey, walletType |
sessionConfig.sessionPublicKey | string | Yes | From createSessionKey().publicKey |
sessionConfig.validUntil | number | Yes | Unix timestamp when session expires |
sessionConfig.maxCalls | number | Yes | Maximum transactions allowed |
sessionConfig.allowedEntrypoints | string[] | Yes | Whitelisted function selectors (empty = all) |
Restricting Permissions
For enhanced security, whitelist specific function selectors:
const txHash = await browserClient.sessions.addSessionKeyToContract({
encryptKey: pin,
wallet: walletData,
sessionConfig: {
sessionPublicKey: session.publicKey,
validUntil: session.validUntil,
maxCalls: 10,
allowedEntrypoints: [
"0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", // transfer
"0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", // approve
],
},
}, bearerToken);
revokeSessionKey
Revoke a session key from the smart contract. After revocation, the session can no longer execute transactions.
const bearerToken = await getBearerToken();
const txHash = await browserClient.sessions.revokeSessionKey({
encryptKey: "user-secure-pin",
wallet: {
publicKey: wallet.publicKey,
encryptedPrivateKey: wallet.encryptedPrivateKey,
walletType: "CHIPI",
},
sessionPublicKey: session.publicKey,
}, bearerToken);
// Clear from local storage
localStorage.removeItem('chipiSession');
console.log("Session revoked:", txHash);
Parameters
| Parameter | Type | Required | Description |
|---|
encryptKey | string | Yes | Owner’s PIN to sign the revocation |
wallet | WalletData | Yes | Wallet object |
sessionPublicKey | string | Yes | Public key of session to revoke |
Always revoke sessions when a user logs out to prevent unauthorized access.
getSessionData
Query session status from the smart contract. This is a read-only operation that doesn’t require gas.
const sessionData = await browserClient.sessions.getSessionData({
walletAddress: wallet.publicKey,
sessionPublicKey: session.publicKey,
});
console.log(sessionData);
// {
// isActive: true,
// validUntil: 1702500000,
// remainingCalls: 95,
// allowedEntrypoints: []
// }
if (sessionData.isActive) {
console.log(`Session has ${sessionData.remainingCalls} calls remaining`);
}
Parameters
| Parameter | Type | Required | Description |
|---|
walletAddress | string | Yes | Wallet address to query |
sessionPublicKey | string | Yes | Session public key to query |
Return Value
{
isActive: boolean; // Whether session is valid
validUntil: number; // Expiration timestamp
remainingCalls: number; // Transactions remaining
allowedEntrypoints: string[]; // Whitelisted functions
}
executeTransactionWithSession
Execute a transaction using a session key instead of the owner private key. No wallet popup required!
const bearerToken = await getBearerToken();
const session = JSON.parse(localStorage.getItem('chipiSession')!);
const txHash = await browserClient.executeTransactionWithSession({
params: {
encryptKey: "user-secure-pin",
wallet: {
publicKey: wallet.publicKey,
encryptedPrivateKey: wallet.encryptedPrivateKey,
walletType: "CHIPI",
},
session,
calls: [
{
contractAddress: "0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8",
entrypoint: "transfer",
calldata: [recipientAddress, amount, "0x0"],
},
],
},
bearerToken,
});
console.log("Transaction executed:", txHash);
Parameters
| Parameter | Type | Required | Description |
|---|
params.encryptKey | string | Yes | PIN to decrypt the session private key |
params.wallet | WalletData | Yes | Wallet the session acts on behalf of |
params.session | SessionKeyData | Yes | Session from createSessionKey() |
params.calls | Call[] | Yes | Array of contract calls |
bearerToken | string | Yes | Authentication token |
Call Structure
{
contractAddress: string; // Target contract address
entrypoint: string; // Function name
calldata: string[]; // Function arguments
}
Multi-Call Example
Execute multiple operations in a single transaction:
const txHash = await browserClient.executeTransactionWithSession({
params: {
encryptKey: pin,
wallet: walletData,
session,
calls: [
// Approve spending
{
contractAddress: USDC_ADDRESS,
entrypoint: "approve",
calldata: [SWAP_CONTRACT, amount, "0x0"],
},
// Execute swap
{
contractAddress: SWAP_CONTRACT,
entrypoint: "swap",
calldata: [USDC_ADDRESS, ETH_ADDRESS, amount, minReceived],
},
],
},
bearerToken,
});
Complete Example: Gaming Session
import { ChipiBrowserSDK } from "@chipi-stack/backend";
const browserClient = new ChipiBrowserSDK({
apiPublicKey: "pk_prod_your_public_key",
});
const GAME_CONTRACT = "0x...";
const MAKE_MOVE_SELECTOR = "0x...";
// Start a gaming session
async function startGameSession(userPin: string, bearerToken: string) {
// Get player's wallet
const wallet = await browserClient.getWallet({ externalUserId: "user-123" }, bearerToken);
// Create 24-hour gaming session
const session = browserClient.sessions.createSessionKey({
encryptKey: userPin,
durationSeconds: 24 * 60 * 60,
});
// Register with game-only permissions
await browserClient.sessions.addSessionKeyToContract({
encryptKey: userPin,
wallet: { ...wallet, walletType: "CHIPI" },
sessionConfig: {
sessionPublicKey: session.publicKey,
validUntil: session.validUntil,
maxCalls: 1000,
allowedEntrypoints: [MAKE_MOVE_SELECTOR],
},
}, bearerToken);
// Store session
localStorage.setItem('gameSession', JSON.stringify(session));
return session;
}
// Make a move instantly - no wallet popup!
async function makeMove(moveData: string, userPin: string, bearerToken: string) {
const session = JSON.parse(localStorage.getItem('gameSession')!);
const wallet = await browserClient.getWallet({ externalUserId: "user-123" }, bearerToken);
return browserClient.executeTransactionWithSession({
params: {
encryptKey: userPin,
wallet: { ...wallet, walletType: "CHIPI" },
session,
calls: [{
contractAddress: GAME_CONTRACT,
entrypoint: "make_move",
calldata: [moveData],
}],
},
bearerToken,
});
}
// Secure logout
async function logout(userPin: string, bearerToken: string) {
const sessionStr = localStorage.getItem('gameSession');
if (sessionStr) {
const session = JSON.parse(sessionStr);
const wallet = await browserClient.getWallet({ externalUserId: "user-123" }, bearerToken);
try {
await browserClient.sessions.revokeSessionKey({
encryptKey: userPin,
wallet: { ...wallet, walletType: "CHIPI" },
sessionPublicKey: session.publicKey,
}, bearerToken);
} catch (e) {
console.warn("Failed to revoke session:", e);
}
localStorage.removeItem('gameSession');
}
}
Error Handling
| Error | Cause | Solution |
|---|
Session keys require CHIPI wallet type | Wallet is ARGENT type | Create wallet with walletType: "CHIPI" |
Invalid encryptKey | Wrong PIN | Verify PIN matches wallet creation |
Session has expired | validUntil passed | Create and register a new session |
Max calls exceeded | remainingCalls is 0 | Create new session with higher maxCalls |
Entrypoint not allowed | Function not whitelisted | Register session with correct allowedEntrypoints |
Security Best Practices
- Short durations - Use 1-6 hours, not days
- Limit calls - Set realistic
maxCalls based on expected usage
- Whitelist functions - Restrict
allowedEntrypoints to only what your app needs
- Revoke on logout - Always clean up sessions when user signs out
- Client-side storage only - Never store session keys in your database