Wallets

Session Keys Guide

Session keys enable secure transaction execution on behalf of accounts without requiring direct access to the main account's private key. This guide covers session keys for both ERC-4337 smart accounts and ERC-7702 smart EOAs (Externally Owned Accounts).

Prerequisites

Before you begin, ensure you have:

  • A thirdweb client configured
  • An in-app wallet with ERC-7702 support
  • A session key account address (can be generated or an existing wallet)

Setup

First, let's set up the necessary imports and configuration:

import {
createThirdwebClient,
getContract,
sendTransaction,
prepareTransaction,
} from "thirdweb";
import { sepolia } from "thirdweb/chains";
import {
inAppWallet,
createSessionKey,
} from "thirdweb/wallets/in-app";
// Configure your client
const client = createThirdwebClient({
clientId: "your-client-id",
secretKey: "your-secret-key", // Only use in server environments
});
// Your session key account address
const sessionKeyAccountAddress = "0x..."; // Replace with your session key address (server wallet)

Step 1: Create ERC-7702 Smart EOA

Create an in-app wallet configured with ERC-7702 execution mode:

const wallet = inAppWallet({
executionMode: {
mode: "EIP7702",
sponsorGas: true, // Enable gas sponsorship
},
});
// Connect the wallet (user authentication)
const account = await wallet.connect({
chain: sepolia,
client: client,
strategy: "google", // or "email", "guest", etc.
});
console.log("Upgraded EOA address:", account.address);

Execution Modes

The executionMode option allows you to configure the wallet behavior:

  • mode: Set to "EIP7702" for EIP-7702 upgraded EOA functionality
  • sponsorGas: Enable gas sponsorship for gasless transactions

Step 2: Get Account Contract

Create a contract instance for the deployed smart EOA:

const accountContract = getContract({
address: account.address,
chain: sepolia,
client: client,
});

Step 3: Create Session Key with Full Permissions

Add a session key with full execution permissions:

const tx = await sendTransaction({
account: account,
transaction: createSessionKey({
account: account,
contract: accountContract,
sessionKeyAddress: sessionKeyAccountAddress,
durationInSeconds: 86400, // 1 day
grantFullPermissions: true, // Allow unrestricted access
}),
});
console.log("Session key created:", tx.transactionHash);

Session Key Options

  • account: The admin account that will create the session key
  • contract: The smart EOA contract instance
  • sessionKeyAddress: The address that will be granted session key permissions
  • durationInSeconds: How long the session key should be valid (in seconds)
  • grantFullPermissions: If true, grants unrestricted access. If false, you must specify policies.

Step 4 (Advanced): Create Session Key with Granular Permissions

For more fine-grained control, you can specify call and transfer policies:

import { Condition, LimitType } from "thirdweb/wallets/in-app";
const tx = await sendTransaction({
account: account,
transaction: createSessionKey({
account: account,
contract: accountContract,
sessionKeyAddress: sessionKeyAccountAddress,
durationInSeconds: 86400, // 1 day
grantFullPermissions: false, // Use granular permissions
callPolicies: [
{
target: "0x123...", // Target contract address
selector: "0xa9059cbb", // Function selector (e.g., ERC20 transfer)
maxValuePerUse: 0n, // Max ETH value per call
valueLimit: {
limitType: LimitType.Lifetime, // Lifetime limit
limit: 1000000n, // Max total value in wei
period: 0n, // Not used for lifetime limits
},
constraints: [
{
condition: Condition.Equal, // Constraint type
index: 0n, // Parameter index
refValue: "0x000000000000000000000000abc...", // Expected value
},
],
},
],
transferPolicies: [
{
target: "0x456...", // Recipient address for transfers
maxValuePerUse: 100000n, // Max wei per transfer
valueLimit: {
limitType: LimitType.Allowance, // Allowance-based limit
limit: 1000000n, // Total allowance in wei
period: 86400n, // Reset period in seconds
},
},
],
}),
});
console.log("Session key with policies created:", tx.transactionHash);

Permission Types

Call Policies

Control which smart contract calls the session key can make:

  • target: The contract address the session key can call
  • selector: The function selector (4-byte identifier) that can be called
  • maxValuePerUse: Maximum ETH value that can be sent per transaction
  • valueLimit: Total value limits over time
  • constraints: Parameter-level constraints for function calls

Transfer Policies

Control native token transfers the session key can make:

  • target: The recipient address for transfers
  • maxValuePerUse: Maximum wei per individual transfer
  • valueLimit: Total transfer limits over time

Limit Types

enum LimitType {
Unlimited = 0, // No limit
Lifetime = 1, // One-time total limit
Allowance = 2, // Renewable allowance based on period
}

Constraint Conditions

enum Condition {
Unconstrained = 0, // No constraint
Equal = 1, // Must equal reference value
Greater = 2, // Must be greater than reference value
Less = 3, // Must be less than reference value
GreaterOrEqual = 4, // Must be >= reference value
LessOrEqual = 5, // Must be <= reference value
NotEqual = 6, // Must not equal reference value
}

Step 5: Use the Session Key

Once created, the session key can be used with Engine or other server-side execution:

import { Engine } from "thirdweb/engine";
const serverWallet = Engine.serverWallet({
address: sessionKeyAccountAddress,
chain: sepolia,
client: client,
});
// Execute transactions with the session key
const tx = await sendTransaction({
account: serverWallet,
transaction: prepareTransaction({
chain: sepolia,
client: client,
to: "0x...", // Target address
value: 0n,
}),
});
console.log("Transaction executed:", tx.transactionHash);

Complete Example

Here's a complete example for setting up and using a session key with ERC-7702:

import {
createThirdwebClient,
getContract,
sendTransaction,
prepareTransaction,
} from "thirdweb";
import { sepolia } from "thirdweb/chains";
import {
inAppWallet,
createSessionKey,
} from "thirdweb/wallets/in-app";
import { Engine } from "thirdweb/engine";
async function setupSessionKeyWith7702() {
// Configuration
const client = createThirdwebClient({
clientId: "your-client-id",
secretKey: "your-secret-key",
});
const sessionKeyAccountAddress = "0x..."; // Your session key address (server wallet)
try {
// Step 1: Create 7702 Smart EOA
const wallet = inAppWallet({
executionMode: {
mode: "EIP7702",
sponsorGas: true,
},
});
const account = await wallet.connect({
chain: sepolia,
client: client,
strategy: "google",
});
console.log("Upgraded EOA created:", account.address);
// Step 2: Get account contract
const accountContract = getContract({
address: account.address,
chain: sepolia,
client: client,
});
// Step 3: Create session key
const sessionTx = await sendTransaction({
account: account,
transaction: createSessionKey({
account: account,
contract: accountContract,
sessionKeyAddress: sessionKeyAccountAddress,
durationInSeconds: 86400, // 1 day
grantFullPermissions: true,
}),
});
console.log("Session key created:", sessionTx.transactionHash);
// Step 4: Use the session key with Engine
const serverWallet = Engine.serverWallet({
address: sessionKeyAccountAddress,
chain: sepolia,
client: client,
});
// Execute a transaction with the session key
const tx = await sendTransaction({
account: serverWallet,
transaction: prepareTransaction({
chain: sepolia,
client: client,
to: "0x...", // Target address
value: 0n,
}),
});
console.log("Transaction successful:", tx.transactionHash);
return tx;
} catch (error) {
console.error("Error:", error);
throw error;
}
}
// Execute the function
setupSessionKeyWith7702()
.then((tx) => console.log("Done!", tx.transactionHash))
.catch((error) => console.error("Failed:", error));

Security Considerations

  • Session Key Storage: Store session keys securely, preferably in a vault system
  • Permission Scope: Use granular permissions (grantFullPermissions: false) for production use cases
  • Time Limits: Set appropriate durationInSeconds values based on your use case
  • Policy Design: Carefully design call and transfer policies to minimize risk
  • Key Rotation: Regularly rotate session keys and revoke unused ones
  • Monitoring: Monitor session key usage for suspicious activity

Troubleshooting

Common Issues

  • Account not deployed: Ensure you've sent a transaction to trigger the account deployment/upgrade
  • Invalid signature: Make sure the admin account is properly authenticated and can sign typed data
  • Permission denied: Verify the session key has the necessary policies for the operation
  • Expired session key: Check that the current time is within the session key's validity period

Next Steps