Skip to main content

What Are Session Keys?

Session keys are temporary keypairs that let your app execute transactions on behalf of a user without requiring their private key for every action. Instead of prompting users to sign each transaction, you register a session key on-chain with specific permissions (time limit, call limit, allowed functions) and then use it silently. This enables gasless, popup-free UX for gaming, DeFi automation, social apps, and subscriptions.
Session keys only work with CHIPI wallets (SNIP-9 compatible). They are not supported on READY wallets.

When to Use Session Keys

Use CaseWhy Sessions Help
GamingPlayers make moves without wallet popups
DeFi automationYield optimizers execute strategies automatically
Social dAppsPost, like, comment without friction
SubscriptionsRecurring payments without manual approval
AirdropsZero-friction claiming

How It Works

1. Create    → Generate a session keypair locally (client-side only)
2. Register  → Register the session on the CHIPI wallet contract (one-time, requires owner signature)
3. Execute   → Use the session key to sign transactions (no owner key needed)
4. Monitor   → Check remaining calls and expiration
5. Revoke    → Revoke the session on logout or expiration
The SDK handles the signature format difference automatically:
  • Owner signature: [r, s] (2 elements)
  • Session signature: [sessionPubKey, r, s, validUntil] (4 elements)

Frontend Implementation

1. Create a Session Key

import { useCreateSessionKey } from "@chipi-stack/nextjs";

function StartSession() {
  const { createSessionKeyAsync, isLoading } = useCreateSessionKey();

  const handleStart = async () => {
    const session = await createSessionKeyAsync({
      encryptKey: userPin,
      durationSeconds: 3600, // 1 hour
    });

    // Store in client-side storage only (NEVER in your database)
    localStorage.setItem("chipiSession", JSON.stringify(session));
  };
}

2. Register On-Chain

import { useAddSessionKeyToContract } from "@chipi-stack/nextjs";

function RegisterSession() {
  const { addSessionKeyToContractAsync } = useAddSessionKeyToContract();

  const handleRegister = async () => {
    const session = JSON.parse(localStorage.getItem("chipiSession")!);
    const bearerToken = await getBearerToken();

    await addSessionKeyToContractAsync({
      params: {
        encryptKey: userPin,
        wallet: { publicKey: wallet.publicKey, encryptedPrivateKey: wallet.encryptedPrivateKey, walletType: "CHIPI" },
        sessionConfig: {
          sessionPublicKey: session.publicKey,
          validUntil: session.validUntil,
          maxCalls: 100,
          allowedEntrypoints: [], // empty = all functions allowed
        },
      },
      bearerToken,
    });
  };
}

3. Execute Transactions

import { useExecuteWithSession } from "@chipi-stack/nextjs";

const USDC = "0x033068F6539f8e6e6b131e6B2B814e6c34A5224bC66947c47DaB9dFeE93b35fb";

function TransferWithSession() {
  const { executeWithSessionAsync, isLoading } = useExecuteWithSession();

  const handleTransfer = async (recipient: string, amount: string) => {
    const session = JSON.parse(localStorage.getItem("chipiSession")!);
    const bearerToken = await getBearerToken();

    const txHash = await executeWithSessionAsync({
      params: {
        encryptKey: userPin,
        wallet: { publicKey: wallet.publicKey, encryptedPrivateKey: wallet.encryptedPrivateKey, walletType: "CHIPI" },
        session,
        calls: [{
          contractAddress: USDC,
          entrypoint: "transfer",
          calldata: [recipient, amount, "0x0"],
        }],
      },
      bearerToken,
    });
  };
}

4. Check Session Status

import { useGetSessionData } from "@chipi-stack/nextjs";

function SessionStatus() {
  const { data: sessionData } = useGetSessionData({
    walletAddress: wallet.publicKey,
    sessionPublicKey: session.publicKey,
  });

  if (sessionData?.isActive) {
    return <p>{sessionData.remainingCalls} calls remaining</p>;
  }
  return <p>Session expired or revoked</p>;
}

5. Revoke on Logout

import { useRevokeSessionKey } from "@chipi-stack/nextjs";

function LogoutButton() {
  const { revokeSessionKeyAsync } = useRevokeSessionKey();

  const handleLogout = async () => {
    const session = JSON.parse(localStorage.getItem("chipiSession")!);

    try {
      await revokeSessionKeyAsync({
        params: {
          encryptKey: userPin,
          wallet: { publicKey: wallet.publicKey, encryptedPrivateKey: wallet.encryptedPrivateKey, walletType: "CHIPI" },
          sessionPublicKey: session.publicKey,
        },
        bearerToken: await getBearerToken(),
      });
    } catch {
      // Continue with logout even if revoke fails
    }

    localStorage.removeItem("chipiSession");
    await authProvider.signOut();
  };
}

Session Configuration

ParameterTypeDescription
sessionPublicKeystringPublic key from createSessionKey()
validUntilnumberUnix timestamp (seconds) when session expires
maxCallsnumberMaximum transactions allowed (decrements with each use)
allowedEntrypointsstring[]Whitelisted function selectors. Empty = all allowed

Restricting Permissions

For security, whitelist specific entrypoints:
sessionConfig: {
  sessionPublicKey: session.publicKey,
  validUntil: session.validUntil,
  maxCalls: 10,
  allowedEntrypoints: [
    "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", // transfer
    "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", // approve
  ],
}

Security Best Practices

Never store session keys in your backend database. This defeats self-custodial security. Store only in client-side secure storage.
PlatformRecommended Storage
WeblocalStorage or sessionStorage
iOSSecure Enclave / Keychain
AndroidAndroid Keystore
React Nativeexpo-secure-store
  1. Always revoke on logout - Never leave active sessions
  2. Set short durations - 1-6 hours, not days
  3. Limit maxCalls - Set realistic limits based on expected usage
  4. Whitelist entrypoints - Restrict to only the functions your app needs
  5. Monitor remaining calls - Create new sessions before exhaustion
Need help? Join our Telegram Community for support.