> ## Documentation Index
> Fetch the complete documentation index at: https://docs.chipipay.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Session Keys Quickstart

> Enable temporary, delegated transaction execution without requiring the owner's private key for each operation

> [!WARNING]
>
> **PIN is weak — not recommended for production.**
>
> A user-typed PIN is a short, low-entropy string. Anyone who shoulder-surfs the PIN, observes a phishing form, or compromises the browser at typing time can decrypt the wallet's private key. PIN remains in the SDK only as a fallback recovery surface for users who lose access to their platform authenticator.
>
> **Production embedded-wallet apps should default to a platform passkey** (Touch ID, Face ID, Windows Hello, Android biometrics) via the `@chipi-stack/chipi-passkey` package. For SHHH V8.4 wallets, `signerKind: "WEBAUTHN_P256"` keeps the private key inside the platform authenticator — it never leaves the device, never reaches Chipi servers, and is never derived from a user-typed secret.
>
> Only prompt for a PIN as the encryption key when:
>
> * The user explicitly opted into a PIN-only flow (e.g. cold-storage / paper-backup recovery), or
> * The platform genuinely has no WebAuthn / biometric support available.
>
> If you are migrating an existing PIN-based wallet to a passkey, look up `useMigrateWalletToPasskey` in your framework's hook docs.

## What are Session Keys?

Session keys allow your application to execute transactions on behalf of a user without requiring their owner private key for every action. Instead, a temporary keypair is created and registered on-chain with specific permissions (time limit, call limit, allowed functions).

This enables **gasless, frictionless UX** for gaming, DeFi automation, social apps, and more.

> [!NOTE]
>
> Session keys only work with [CHIPI wallets](https://github.com/chipi-pay/sessions-smart-contract) - OpenZeppelin accounts extended with SNIP-9 session key support.

## When to Use Session Keys

| Use Case | Why Sessions Help |
| - | - |
| **Gaming** | Players make moves without wallet popups |
| **DeFi Automation** | Yield optimizers execute strategies automatically |
| **Social dApps** | Post, like, comment without friction |
| **Subscriptions** | Recurring payments without manual approval |
| **Airdrops** | Zero-friction claiming for users |

## Requirements

* A [CHIPI wallet](https://github.com/chipi-pay/sessions-smart-contract) (not READY)
* Valid bearer token from your auth provider
* User's `encryptKey` (PIN) for signing

***

## 1. Install the Backend SDK

```bash npm theme={null}
npm install @chipi-stack/backend
```

```bash yarn theme={null}
yarn add @chipi-stack/backend
```

```bash pnpm theme={null}
pnpm add @chipi-stack/backend
```

## 2. Initialize the SDK

```typescript theme={null}
import { ChipiSDK } from "@chipi-stack/backend";

const sdk = new ChipiSDK({
  apiPublicKey: process.env.CHIPI_PUBLIC_KEY!,
  apiSecretKey: process.env.CHIPI_SECRET_KEY!,
});
```

## 3. Create a Session Key

Generate a session keypair locally. The SDK returns the data but does **NOT** store it - you must persist it on the client side.

```typescript theme={null}
// Create session key (self-custodial - store in client localStorage)
const session = sdk.sessions.createSessionKey({
  encryptKey: "user-secure-pin",
  durationSeconds: 3600, // 1 hour (default: 6 hours)
});

console.log(session);
// {
//   publicKey: "0x...",           // Session public key
//   encryptedPrivateKey: "...",   // AES encrypted with encryptKey
//   validUntil: 1702500000        // Unix timestamp (seconds)
// }

// Store in client-side secure storage (NOT your database!)
localStorage.setItem('chipiSession', JSON.stringify(session));
```

> [!CAUTION]
>
> Never store session keys in your backend database. Store only in client-side secure storage (localStorage, Secure Enclave, Keychain).

## 4. Register Session On-Chain

Before using a session key, you must register it on the [CHIPI wallet](https://github.com/chipi-pay/sessions-smart-contract) smart contract. This requires the owner's signature (one-time setup).

```typescript theme={null}
// Get user's wallet
const wallet = await sdk.getWallet({ externalUserId: "user-123" });

// Register session on contract (uses owner signature via paymaster)
const txHash = await sdk.sessions.addSessionKeyToContract({
  encryptKey: "user-secure-pin",
  wallet: {
    publicKey: wallet.publicKey,
    encryptedPrivateKey: wallet.encryptedPrivateKey,
    walletType: "CHIPI",
  },
  sessionConfig: {
    sessionPublicKey: session.publicKey,
    validUntil: session.validUntil,
    maxCalls: 100,                // Max transactions allowed
    allowedEntrypoints: [],       // Empty = all functions allowed
  },
}, bearerToken);

console.log("Session registered:", txHash);
```

### Session Configuration Options

| Parameter | Type | Description |
| - | - | - |
| `sessionPublicKey` | string | Public key from `createSessionKey()` |
| `validUntil` | number | Unix timestamp when session expires |
| `maxCalls` | number | Maximum transactions allowed (decrements with each use) |
| `allowedEntrypoints` | string\[] | Function names (`"transfer"`) or hex selectors. Names are converted to selectors (14.13.1+). A selector is allowed on every contract, not just one. Empty = all allowed |

> [!TIP]
>
> For security, whitelist specific entrypoints when possible:
>
> ```typescript theme={null}
> allowedEntrypoints: [
>   "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", // transfer
>   "0x219209e083275171774dab1df80982e9df2096516f06319c5c6d71ae0a8480c", // approve
> ]
> ```

## 5. Execute Transactions with Session

Now you can execute transactions using the session key - **no owner private key needed!**

```typescript theme={null}
// Retrieve session from client storage
const session = JSON.parse(localStorage.getItem('chipiSession')!);

// Execute transaction with session signature (4-element format)
const txHash = await sdk.executeTransactionWithSession({
  params: {
    encryptKey: "user-secure-pin",
    wallet: {
      publicKey: wallet.publicKey,
      encryptedPrivateKey: wallet.encryptedPrivateKey,
      walletType: "CHIPI",
    },
    session,
    calls: [
      {
        contractAddress: "0x049d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
        entrypoint: "transfer",
        calldata: [recipientAddress, amount, "0x0"],
      },
    ],
  },
  bearerToken,
});

console.log("Transaction executed:", txHash);
```

> [!NOTE]
>
> **Signature Format Difference:**
>
> * Owner signature: `[r, s]` (2 elements)
> * Session signature: `[sessionPubKey, r, s, validUntil]` (4 elements)
>
> The SDK handles this automatically.

## 6. Query Session Status

Check if a session is still active and how many calls remain:

```typescript theme={null}
const sessionData = await sdk.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`);
}
```

## 7. Revoke Session

Always revoke sessions when no longer needed or when the user logs out:

```typescript theme={null}
const revokeTxHash = await sdk.sessions.revokeSessionKey({
  encryptKey: "user-secure-pin",
  wallet: {
    publicKey: wallet.publicKey,
    encryptedPrivateKey: wallet.encryptedPrivateKey,
    walletType: "CHIPI",
  },
  sessionPublicKey: session.publicKey,
}, bearerToken);

// Clear from client storage
localStorage.removeItem('chipiSession');

console.log("Session revoked:", revokeTxHash);
```

> [!WARNING]
>
> Always revoke sessions on logout to prevent unauthorized access.

***

## Security and Best Practices

### Storage Guidelines

> [!CAUTION]
>
> **Never store session keys in your backend database.** This defeats the purpose of self-custodial security.

Store session keys only in client-side secure storage:

| Platform | Recommended Storage |
| - | - |
| **Web** | `localStorage` or `sessionStorage` |
| **iOS** | Secure Enclave / Keychain |
| **Android** | Android Keystore |
| **React Native** | `expo-secure-store` or `react-native-keychain` |

> [!TIP]
>
> Use `sessionStorage` instead of `localStorage` for sessions that should expire when the browser tab closes.

### Lifecycle Best Practices

1. **Always revoke on logout** - Never leave active sessions when user signs out
2. **Set short durations** - Use 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

### Example: Secure Logout Handler

```typescript theme={null}
const handleLogout = async () => {
  // Retrieve active session
  const sessionStr = localStorage.getItem('chipiSession');
  
  if (sessionStr) {
    const session = JSON.parse(sessionStr);
    
    try {
      // Revoke session on-chain before logout
      await sdk.sessions.revokeSessionKey({
        encryptKey: userPin,
        wallet,
        sessionPublicKey: session.publicKey,
      }, bearerToken);
    } catch (error) {
      console.warn("Failed to revoke session:", error);
      // Continue with logout even if revoke fails
    }
    
    // Clear from local storage
    localStorage.removeItem('chipiSession');
  }
  
  // Proceed with auth logout
  await authProvider.signOut();
};
```

### Example: Session with Restricted Permissions

```typescript theme={null}
// Create a session that can ONLY transfer USDC
const restrictedSession = await sdk.sessions.addSessionKeyToContract({
  encryptKey: userPin,
  wallet,
  sessionConfig: {
    sessionPublicKey: session.publicKey,
    validUntil: session.validUntil,
    maxCalls: 10,  // Only 10 transfers allowed
    allowedEntrypoints: [
      "0x83afd3f4caedc6eebf44246fe54e38c95e3179a5ec9ea81740eca5b482d12e", // transfer
    ],
  },
}, bearerToken);
```

***

## Full Example: Gaming Session

```typescript theme={null}
import { ChipiSDK } from "@chipi-stack/backend";

const sdk = new ChipiSDK({
  apiPublicKey: process.env.CHIPI_PUBLIC_KEY!,
  apiSecretKey: process.env.CHIPI_SECRET_KEY!,
});

// Game constants
const GAME_CONTRACT = "0x...";
const MAKE_MOVE_SELECTOR = "0x...";
const CLAIM_REWARD_SELECTOR = "0x...";

async function startGameSession(userId: string, userPin: string, bearerToken: string) {
  // Get player's CHIPI wallet
  const wallet = await sdk.getWallet({ externalUserId: userId });
  
  // Create 24-hour gaming session
  const session = sdk.sessions.createSessionKey({
    encryptKey: userPin,
    durationSeconds: 24 * 60 * 60, // 24 hours
  });
  
  // Register with game-only permissions
  await sdk.sessions.addSessionKeyToContract({
    encryptKey: userPin,
    wallet: { ...wallet, walletType: "CHIPI" },
    sessionConfig: {
      sessionPublicKey: session.publicKey,
      validUntil: session.validUntil,
      maxCalls: 1000,  // Many moves allowed
      allowedEntrypoints: [MAKE_MOVE_SELECTOR, CLAIM_REWARD_SELECTOR],
    },
  }, bearerToken);
  
  // Store session in client
  localStorage.setItem('gameSession', JSON.stringify(session));
  
  return session;
}

async function makeMove(moveData: string, bearerToken: string) {
  const session = JSON.parse(localStorage.getItem('gameSession')!);
  const wallet = await sdk.getWallet({ externalUserId: currentUserId });
  
  // Execute move instantly - no wallet popup!
  return sdk.executeTransactionWithSession({
    params: {
      encryptKey: userPin,
      wallet: { ...wallet, walletType: "CHIPI" },
      session,
      calls: [{
        contractAddress: GAME_CONTRACT,
        entrypoint: "make_move",
        calldata: [moveData],
      }],
    },
    bearerToken,
  });
}
```

***

## Next Steps

* **[Session Methods Reference](/sdk/backend/methods/sessions)** - Detailed API for each session method
* **[CHIPI Wallet Smart Contract](https://github.com/chipi-pay/sessions-smart-contract)** - Cairo implementation details
* **[Transfer Tokens](/sdk/backend/methods/transfer)** - Basic token transfers

> [!TIP]
>
> Need help? Join our [Telegram Community](https://t.me/+e2qjHEOwImkyZDVh) for support.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.