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

# Smart sessions

> Issue scoped, time-limited session keys to remove signature friction from your dApp.

Smart sessions let your dapp act on the user's behalf within an explicit policy: a set of allowed contracts, function selectors, and an expiry. The user signs **once** to grant the session; afterwards every UserOperation that fits inside the policy can be executed by a session signer without prompting the user again.

Smart sessions are implemented as an [ERC-7579](https://eips.ethereum.org/EIPS/eip-7579) **validator module**. The Startale AA SDK ships first-party helpers around the [Rhinestone Smart Sessions module](https://docs.rhinestone.wtf/) so you can install it and grant permissions through the same `StartaleAccountClient` you already use.

<Note>
  Source: [`StartaleGroup/scs-aa-sdk`](https://github.com/StartaleGroup/scs-aa-sdk). The flow below mirrors the production integration in the Startale super-app.
</Note>

## How it fits together

```mermaid theme={null}
flowchart LR
  Owner[Account owner]
  SA[Startale Smart Account]
  SM[Smart Sessions module<br/>ERC-7579 validator]
  SK[Session key<br/>(scoped signer)]
  Target[(Target contract)]

  Owner -->|installModule| SM
  SM --> SA
  Owner -->|grantPermission(scope)| SM
  SK -->|UserOp validated by SM| SA
  SA -->|call| Target
```

Two artefacts come out of the granting step:

* A **permission id** that identifies the policy onchain.
* A **session key** keypair. The public key is committed to the policy; the private key is used by your backend or browser to sign UserOperations within scope.

## 1. Check whether the module is installed

`getSmartSessionsValidator` builds the validator descriptor. The module is keyed by its onchain address, so you can call `isModuleInstalled` on the account client to check status before installing.

```ts theme={null}
import {
  getSmartSessionsValidator,
  type StartaleAccountClient,
} from "@startale-scs/aa-sdk"

const SMART_SESSIONS_MODULE = "0x00000000008bDABA73cD9815d79069c247Eb4bDA" as const

async function isSmartSessionsInstalled(client: StartaleAccountClient) {
  const sessionModule = getSmartSessionsValidator({})
  sessionModule.address = SMART_SESSIONS_MODULE
  sessionModule.module = SMART_SESSIONS_MODULE
  return client.isModuleInstalled({ module: sessionModule })
}
```

| Symbol                      | Source                                     | Role                                                                    |
| --------------------------- | ------------------------------------------ | ----------------------------------------------------------------------- |
| `getSmartSessionsValidator` | `@startale-scs/aa-sdk`                     | Returns a validator descriptor pre-wired for the Smart Sessions module. |
| `isModuleInstalled`         | `StartaleAccountClient` (ERC-7579 actions) | Reads the account's installed validators onchain.                       |

## 2. Install the module (one-time per account)

If the module is not installed, install it once. Installation is itself a UserOperation, so it goes through your bundler and (optionally) your paymaster.

```ts theme={null}
async function installSmartSessions(client: StartaleAccountClient) {
  const sessionModule = getSmartSessionsValidator({})
  sessionModule.address = SMART_SESSIONS_MODULE
  sessionModule.module = SMART_SESSIONS_MODULE

  const userOpHash = await client.installModule({ module: sessionModule })
  return client.waitForUserOperationReceipt({ hash: userOpHash })
}
```

| Symbol                        | Source                                     | Role                                                           |
| ----------------------------- | ------------------------------------------ | -------------------------------------------------------------- |
| `installModule`               | `StartaleAccountClient` (ERC-7579 actions) | Sends a UserOperation that installs the module on the account. |
| `waitForUserOperationReceipt` | `StartaleAccountClient`                    | Polls the bundler for the receipt.                             |

## 3. Define the permission scope

A session scope is a list of `CreateSessionDataParams`. Each entry binds the session key to a contract and a function selector, with optional onchain policies.

```ts theme={null}
import type { CreateSessionDataParams } from "@startale-scs/aa-sdk"
import type { Address } from "viem"

function buildSessionScope(sessionPublicKey: Address): CreateSessionDataParams[] {
  return [
    {
      sessionPublicKey,
      actionPoliciesInfo: [
        {
          contractAddress: "0x...USDC...",
          functionSelector: "0x095ea7b3", // approve(address,uint256)
          sudo: true,
        },
        {
          contractAddress: "0x...Router...",
          functionSelector: "0xa3443faa", // your target selector
          sudo: true,
        },
      ],
    },
  ]
}
```

| Field                                   | Type      | Notes                                                                                                                        |
| --------------------------------------- | --------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `sessionPublicKey`                      | `Address` | The public key of the session signer. The corresponding private key signs UserOperations within scope.                       |
| `actionPoliciesInfo[].contractAddress`  | `Address` | Contract the session is allowed to call.                                                                                     |
| `actionPoliciesInfo[].functionSelector` | `Hex`     | The 4-byte selector the session is allowed to call on that contract.                                                         |
| `actionPoliciesInfo[].sudo`             | `boolean` | When `true`, allows any arguments. Set to `false` and add granular policies (spending caps, allowlists) for tighter control. |

<Tip>
  Generate the session key with `viem`'s `generatePrivateKey()` + `privateKeyToAccount()` and store the private key wherever you intend to sign from (typically a backend service or a sealed browser store).
</Tip>

## 4. Grant the permission

Granting the permission is also a UserOperation, signed once by the account owner. Use `smartSessionCreateActions` to extend the account client with the granting action, then call `grantPermission`.

```ts theme={null}
import {
  smartSessionCreateActions,
  toSmartSessionsValidator,
  type Signer,
} from "@startale-scs/aa-sdk"
import type { Address, Hex } from "viem"

async function grantSession(
  client: StartaleAccountClient,
  sessionPublicKey: Address,
) {
  const sessionData = buildSessionScope(sessionPublicKey)

  const sessionSigner = toSmartSessionsValidator({
    account: client.account,
    signer: {
      address: sessionPublicKey,
      // Backend or remote signer holds the private key; the frontend uses a noop.
      signMessage: () => Promise.resolve("0x" as Hex),
      signTransaction: () => Promise.resolve("0x" as Hex),
      signTypedData: () => Promise.resolve("0x" as Hex),
      publicKey: "0x" as Hex,
      source: "",
      type: "local",
    } as Signer,
  })

  const response = await client
    .extend(smartSessionCreateActions(sessionSigner))
    .grantPermission({ sessionRequestedInfo: sessionData })

  return {
    permissionIds: response.permissionIds,
    userOpHash: response.userOpHash,
  }
}
```

| Symbol                      | Source                 | Role                                                                                                            |
| --------------------------- | ---------------------- | --------------------------------------------------------------------------------------------------------------- |
| `toSmartSessionsValidator`  | `@startale-scs/aa-sdk` | Builds the per-session validator object bound to the account and the session signer.                            |
| `smartSessionCreateActions` | `@startale-scs/aa-sdk` | Extends `StartaleAccountClient` with `grantPermission`.                                                         |
| `grantPermission`           | extended client action | Sends a UserOperation that registers the policy and returns one permission id per `sessionRequestedInfo` entry. |

## 5. Execute UserOperations under the session

Once granted, build a separate `StartaleAccountClient` whose **signer is the session key**. UserOperations from this client are validated by the Smart Sessions module instead of the account's default validator.

```ts theme={null}
import { http } from "viem"
import { privateKeyToAccount } from "viem/accounts"
import { soneiumMinato } from "viem/chains"
import {
  createSmartAccountClient,
  toStartaleSmartAccount,
} from "@startale-scs/aa-sdk"

const sessionSigner = privateKeyToAccount(SESSION_PRIVATE_KEY)

const sessionAccount = await toStartaleSmartAccount({
  signer: sessionSigner,
  chain: soneiumMinato,
  transport: http(),
  accountAddress: ownerAccountAddress, // same smart account, different signer
})

const sessionClient = createSmartAccountClient({
  account: sessionAccount,
  transport: http(process.env.BUNDLER_URL!),
  client: publicClient,
})

const hash = await sessionClient.sendUserOperation({
  calls: [{ to: routerAddress, data: callData, value: 0n }],
})
```

The user is **not** prompted; the session key signs locally, and the Smart Sessions module decides onchain whether the call is in scope.

## Operational guidance

<Warning>
  Treat session private keys like any other production secret. Keep them on a backend or in a sealed enclave, never in plain `localStorage`. Set the shortest expiry that still produces a good UX, and rotate keys on a schedule.
</Warning>

| Concern    | Recommendation                                                                                            |
| ---------- | --------------------------------------------------------------------------------------------------------- |
| Storage    | Backend KMS, secure enclave, or sealed browser storage.                                                   |
| Rotation   | Issue short sessions (minutes-to-hours for high-risk flows, days for low-risk).                           |
| Revocation | Revoke a permission id by calling the module's revocation flow when a session is compromised.             |
| Auditing   | Persist permission ids alongside `userOpHash` so you can correlate signed sessions with onchain activity. |

## Next steps

<CardGroup cols={2}>
  <Card title="Social recovery" icon="user-shield" href="/aa-sdk/tutorials/social-recovery">
    Combine sessions with a guardian-based recovery module.
  </Card>

  <Card title="Sponsored paymaster" icon="gas-pump" href="/aa-sdk/tutorials/sponsored-tx">
    Sponsor every session UserOperation through the SCS paymaster.
  </Card>

  <Card title="Parallel transactions" icon="bolt" href="/aa-sdk/advanced/parallel-tx">
    Run independent session UserOperations concurrently.
  </Card>

  <Card title="Smart account setup" icon="wallet" href="/aa-sdk/tutorials/smart-account-setup">
    Refresh the underlying account and client setup.
  </Card>
</CardGroup>
